further progress on the new XML processing modules
This commit is contained in:
parent
f721ddd75b
commit
16c0beb27c
10 changed files with 112 additions and 14 deletions
0
lib/pure/htmlparser.nim
Normal file → Executable file
0
lib/pure/htmlparser.nim
Normal file → Executable file
0
lib/pure/httpserver.nim
Normal file → Executable file
0
lib/pure/httpserver.nim
Normal file → Executable file
|
|
@ -197,6 +197,12 @@ proc errorMsgExpected*(my: TXmlParser, tag: string): string =
|
||||||
result = "$1($2, $3) Error: $4" % [
|
result = "$1($2, $3) Error: $4" % [
|
||||||
my.filename, $getLine(my), $getColumn(my), "<$1> expected" % tag]
|
my.filename, $getLine(my), $getColumn(my), "<$1> expected" % tag]
|
||||||
|
|
||||||
|
proc errorMsg*(my: TXmlParser, msg: string): string =
|
||||||
|
## returns an error message with text `msg` in the same format as the
|
||||||
|
## other error messages
|
||||||
|
result = "$1($2, $3) Error: $4" % [
|
||||||
|
my.filename, $getLine(my), $getColumn(my), msg]
|
||||||
|
|
||||||
proc markError(my: var TXmlParser, kind: TXmlError) {.inline.} =
|
proc markError(my: var TXmlParser, kind: TXmlError) {.inline.} =
|
||||||
my.err = kind
|
my.err = kind
|
||||||
my.state = stateError
|
my.state = stateError
|
||||||
|
|
|
||||||
0
lib/pure/unidecode/gen.py
Normal file → Executable file
0
lib/pure/unidecode/gen.py
Normal file → Executable file
0
lib/pure/unidecode/unidecode.dat
Normal file → Executable file
0
lib/pure/unidecode/unidecode.dat
Normal file → Executable file
0
lib/pure/unidecode/unidecode.nim
Normal file → Executable file
0
lib/pure/unidecode/unidecode.nim
Normal file → Executable file
0
lib/pure/xmldom.nim
Normal file → Executable file
0
lib/pure/xmldom.nim
Normal file → Executable file
0
lib/pure/xmldomparser.nim
Normal file → Executable file
0
lib/pure/xmldomparser.nim
Normal file → Executable file
18
lib/pure/xmltree.nim
Normal file → Executable file
18
lib/pure/xmltree.nim
Normal file → Executable file
|
|
@ -18,13 +18,14 @@ type
|
||||||
xnText, ## a text element
|
xnText, ## a text element
|
||||||
xnElement, ## an element with 0 or more children
|
xnElement, ## an element with 0 or more children
|
||||||
xnCData, ## a CDATA node
|
xnCData, ## a CDATA node
|
||||||
|
xnEntity, ## an entity (like ``&thing;``)
|
||||||
xnComment ## an XML comment
|
xnComment ## an XML comment
|
||||||
|
|
||||||
PXmlAttributes* = PStringTable ## an alias for a string to string mapping
|
PXmlAttributes* = PStringTable ## an alias for a string to string mapping
|
||||||
|
|
||||||
TXmlNode {.pure, final, acyclic.} = object
|
TXmlNode {.pure, final, acyclic.} = object
|
||||||
case k: TXmlNodeKind
|
case k: TXmlNodeKind
|
||||||
of xnText, xnComment, xnCData:
|
of xnText, xnComment, xnCData, xnEntity:
|
||||||
fText: string
|
fText: string
|
||||||
of xnElement:
|
of xnElement:
|
||||||
fTag: string
|
fTag: string
|
||||||
|
|
@ -59,10 +60,15 @@ proc newCData*(cdata: string): PXmlNode =
|
||||||
result = newXmlNode(xnCData)
|
result = newXmlNode(xnCData)
|
||||||
result.fText = cdata
|
result.fText = cdata
|
||||||
|
|
||||||
|
proc newEntity*(entity: string): PXmlNode =
|
||||||
|
## creates a new ``PXmlNode`` of kind ``xnEntity`` with the text `entity`.
|
||||||
|
result = newXmlNode(xnCData)
|
||||||
|
result.fText = cdata
|
||||||
|
|
||||||
proc text*(n: PXmlNode): string {.inline.} =
|
proc text*(n: PXmlNode): string {.inline.} =
|
||||||
## gets the associated text with the node `n`. `n` can be a CDATA, Text
|
## gets the associated text with the node `n`. `n` can be a CDATA, Text,
|
||||||
## or comment node.
|
## comment, or entity node.
|
||||||
assert n.k in {xnText, xnComment, xnCData}
|
assert n.k in {xnText, xnComment, xnCData, xnEntity}
|
||||||
result = n.fText
|
result = n.fText
|
||||||
|
|
||||||
proc tag*(n: PXmlNode): string {.inline.} =
|
proc tag*(n: PXmlNode): string {.inline.} =
|
||||||
|
|
@ -181,6 +187,10 @@ proc add*(result: var string, n: PXmlNode, indent = 0, indWidth = 2) =
|
||||||
result.add("<![CDATA[")
|
result.add("<![CDATA[")
|
||||||
result.add(n.fText)
|
result.add(n.fText)
|
||||||
result.add("]]>")
|
result.add("]]>")
|
||||||
|
of xnEntity:
|
||||||
|
result.add('&')
|
||||||
|
result.add(n.fText)
|
||||||
|
result.add(';')
|
||||||
|
|
||||||
proc `$`*(n: PXmlNode): string =
|
proc `$`*(n: PXmlNode): string =
|
||||||
## converts `n` into its string representation.
|
## converts `n` into its string representation.
|
||||||
|
|
|
||||||
102
lib/pure/xmltreeparser.nim
Normal file → Executable file
102
lib/pure/xmltreeparser.nim
Normal file → Executable file
|
|
@ -9,11 +9,87 @@
|
||||||
|
|
||||||
## This module parses an XML document and creates its XML tree representation.
|
## This module parses an XML document and creates its XML tree representation.
|
||||||
|
|
||||||
import streams, parsexml, xmltree
|
import streams, parsexml, strtabs, xmltree, hxmlcommon
|
||||||
|
|
||||||
|
type
|
||||||
|
EInvalidXml* = object of E_Base ## exception that is raised for invalid XML
|
||||||
|
errors*: seq[string] ## all detected parsing errors
|
||||||
|
|
||||||
proc parse*(x: var TXmlParser, father: PXmlNode) =
|
proc raiseInvalidXml(errors: seq[string]) =
|
||||||
|
var e: ref EInvalidXml
|
||||||
|
new(e)
|
||||||
|
e.msg = errors[0]
|
||||||
|
e.errors = errors
|
||||||
|
raise e
|
||||||
|
|
||||||
|
proc addNode(father, son: PXmlNode) =
|
||||||
|
if son != nil: add(father, son)
|
||||||
|
|
||||||
|
proc parse*(x: var TXmlParser, errors: var seq[string]): PXmlNode =
|
||||||
|
case x.kind
|
||||||
|
of xmlComment:
|
||||||
|
result = newComment(x.text)
|
||||||
|
next(x)
|
||||||
|
of xmlCharData, xmlWhitespace:
|
||||||
|
result = newText(x.text)
|
||||||
|
next(x)
|
||||||
|
of xmlPI, xmlSpecial:
|
||||||
|
# we just ignore processing instructions for now
|
||||||
|
next(x)
|
||||||
|
of xmlError:
|
||||||
|
errors.add(errorMsg(x))
|
||||||
|
next(x)
|
||||||
|
of xmlElementStart: ## ``<elem>``
|
||||||
|
result = newElement(x.elementName)
|
||||||
|
next(x)
|
||||||
|
while true:
|
||||||
|
case x.kind
|
||||||
|
of xmlElementEnd:
|
||||||
|
if x.elementName == result.tag:
|
||||||
|
next(x)
|
||||||
|
else:
|
||||||
|
errors.add(errorMsg(x, "</$1> expected" % result.tag))
|
||||||
|
# do not skip it here!
|
||||||
|
break
|
||||||
|
of xmlEof:
|
||||||
|
errors.add(errorMsg(x, "</$1> expected" % result.tag))
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
result.addNode(parse(x, errors))
|
||||||
|
of xmlElementEnd: ## ``</elem>``
|
||||||
|
errors.add(errorMsg(x, "unexpected ending tag: " & x.elementName))
|
||||||
|
of xmlElementOpen: ## ``<elem
|
||||||
|
result = newElement(x.elementName)
|
||||||
|
next(x)
|
||||||
|
result.attr = newStringTable()
|
||||||
|
while true:
|
||||||
|
case x.kind
|
||||||
|
of xmlAttribute:
|
||||||
|
result.attr[x.attrKey] = x.attrValue
|
||||||
|
next(x)
|
||||||
|
of xmlElementClose:
|
||||||
|
next(x)
|
||||||
|
break
|
||||||
|
of xmlError:
|
||||||
|
errors.add(errorMsg(x))
|
||||||
|
next(x)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
errors.add(errorMsg(x, "'>' expected" % result.tag))
|
||||||
|
next(x)
|
||||||
|
break
|
||||||
|
|
||||||
|
of xmlAttribute, xmlElementClose:
|
||||||
|
errors.add(errorMsg(x, "<some_tag> expected")
|
||||||
|
next(x)
|
||||||
|
of xmlCData:
|
||||||
|
result = newCData(x.charData)
|
||||||
|
next(x)
|
||||||
|
of xmlEntity:
|
||||||
|
## &entity;
|
||||||
|
## XXX To implement!
|
||||||
|
next(x)
|
||||||
|
of xmlEof: nil
|
||||||
|
|
||||||
proc parseXml*(s: PStream, filename: string,
|
proc parseXml*(s: PStream, filename: string,
|
||||||
errors: var seq[string]): PXmlNode =
|
errors: var seq[string]): PXmlNode =
|
||||||
|
|
@ -21,27 +97,31 @@ proc parseXml*(s: PStream, filename: string,
|
||||||
## occured parsing error is added to the `errors` sequence.
|
## occured parsing error is added to the `errors` sequence.
|
||||||
var x: TXmlParser
|
var x: TXmlParser
|
||||||
open(x, s, filename, {reportComments})
|
open(x, s, filename, {reportComments})
|
||||||
|
|
||||||
result = newElement("html")
|
|
||||||
while true:
|
while true:
|
||||||
x.next()
|
x.next()
|
||||||
case x.kind
|
case x.kind
|
||||||
of xmlWhitespace: nil # just skip it
|
of xmlElementOpen, xmlElementStart:
|
||||||
of xmlComment:
|
result = parse(x, errors)
|
||||||
result.add(newComment(x.text))
|
break
|
||||||
|
of xmlComment, xmlWhitespace: nil # just skip it
|
||||||
|
of xmlError:
|
||||||
|
errors.add(errorMsg(x))
|
||||||
|
else:
|
||||||
|
errors.add(errorMsg(x, "<some_tag> expected")
|
||||||
|
break
|
||||||
close(x)
|
close(x)
|
||||||
|
|
||||||
proc parseXml*(s: PStream): PXmlNode =
|
proc parseXml*(s: PStream): PXmlNode =
|
||||||
## parses the XTML from stream `s` and returns a ``PXmlNode``. All parsing
|
## parses the XTML from stream `s` and returns a ``PXmlNode``. All parsing
|
||||||
## errors are ignored.
|
## errors are turned into an ``EInvalidXML`` exception.
|
||||||
var errors: seq[string] = @[]
|
var errors: seq[string] = @[]
|
||||||
result = parseXml(s, "unknown_html_doc", errors)
|
result = parseXml(s, "unknown_html_doc", errors)
|
||||||
|
if errors.len > 0: raiseInvalidXMl(errors)
|
||||||
|
|
||||||
proc loadXml*(path: string, reportErrors = false): PXmlNode =
|
proc loadXml*(path: string, reportErrors = false): PXmlNode =
|
||||||
## Loads and parses XML from file specified by ``path``, and returns
|
## Loads and parses XML from file specified by ``path``, and returns
|
||||||
## a ``PXmlNode``. If `reportErrors` is true, the parsing errors are
|
## a ``PXmlNode``. If `reportErrors` is true, the parsing errors are
|
||||||
## ``echo``ed.
|
## ``echo``ed, otherwise an exception is thrown.
|
||||||
var s = newFileStream(path, fmRead)
|
var s = newFileStream(path, fmRead)
|
||||||
if s == nil: raise newException(EIO, "Unable to read file: " & path)
|
if s == nil: raise newException(EIO, "Unable to read file: " & path)
|
||||||
|
|
||||||
|
|
@ -49,4 +129,6 @@ proc loadXml*(path: string, reportErrors = false): PXmlNode =
|
||||||
result = parseXml(s, path, errors)
|
result = parseXml(s, path, errors)
|
||||||
if reportErrors:
|
if reportErrors:
|
||||||
for msg in items(errors): echo(msg)
|
for msg in items(errors): echo(msg)
|
||||||
|
elif errors.len > 0:
|
||||||
|
raiseInvalidXMl(errors)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue