summary refs log tree commit diff stats
path: root/lib/pure/xmlparser.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure/xmlparser.nim')
-rw-r--r--lib/pure/xmlparser.nim115
1 files changed, 66 insertions, 49 deletions
diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim
index 755bfcdbc..2c1e4e37c 100644
--- a/lib/pure/xmlparser.nim
+++ b/lib/pure/xmlparser.nim
@@ -9,33 +9,34 @@
 
 ## This module parses an XML document and creates its XML tree representation.
 
-import streams, parsexml, strtabs, xmltree
+import std/[streams, parsexml, strtabs, xmltree]
 
-type
-  XmlError* = object of ValueError ## exception that is raised
-                                   ## for invalid XML
-    errors*: seq[string]           ## all detected parsing errors
+when defined(nimPreviewSlimSystem):
+  import std/syncio
 
-{.deprecated: [EInvalidXml: XmlError].}
+type
+  XmlError* = object of ValueError ## Exception that is raised
+                                   ## for invalid XML.
+    errors*: seq[string]           ## All detected parsing errors.
 
-proc raiseInvalidXml(errors: seq[string]) = 
+proc raiseInvalidXml(errors: seq[string]) =
   var e: ref XmlError
   new(e)
   e.msg = errors[0]
   e.errors = errors
   raise e
 
-proc addNode(father, son: XmlNode) = 
+proc addNode(father, son: XmlNode) =
   if son != nil: add(father, son)
 
-proc parse(x: var XmlParser, errors: var seq[string]): XmlNode
+proc parse(x: var XmlParser, errors: var seq[string]): XmlNode {.gcsafe.}
 
-proc untilElementEnd(x: var XmlParser, result: XmlNode, 
+proc untilElementEnd(x: var XmlParser, result: XmlNode,
                      errors: var seq[string]) =
   while true:
     case x.kind
-    of xmlElementEnd: 
-      if x.elementName == result.tag: 
+    of xmlElementEnd:
+      if x.elementName == result.tag:
         next(x)
       else:
         errors.add(errorMsg(x, "</" & result.tag & "> expected"))
@@ -49,7 +50,7 @@ proc untilElementEnd(x: var XmlParser, result: XmlNode,
 
 proc parse(x: var XmlParser, errors: var seq[string]): XmlNode =
   case x.kind
-  of xmlComment: 
+  of xmlComment:
     result = newComment(x.charData)
     next(x)
   of xmlCharData, xmlWhitespace:
@@ -61,17 +62,17 @@ proc parse(x: var XmlParser, errors: var seq[string]): XmlNode =
   of xmlError:
     errors.add(errorMsg(x))
     next(x)
-  of xmlElementStart:    ## ``<elem>``
+  of xmlElementStart: ## ``<elem>``
     result = newElement(x.elementName)
     next(x)
     untilElementEnd(x, result, errors)
   of xmlElementEnd:
     errors.add(errorMsg(x, "unexpected ending tag: " & x.elementName))
-  of xmlElementOpen: 
+  of xmlElementOpen:
     result = newElement(x.elementName)
     next(x)
     result.attrs = newStringTable()
-    while true: 
+    while true:
       case x.kind
       of xmlAttribute:
         result.attrs[x.attrKey] = x.attrValue
@@ -91,25 +92,25 @@ proc parse(x: var XmlParser, errors: var seq[string]): XmlNode =
   of xmlAttribute, xmlElementClose:
     errors.add(errorMsg(x, "<some_tag> expected"))
     next(x)
-  of xmlCData: 
+  of xmlCData:
     result = newCData(x.charData)
     next(x)
   of xmlEntity:
     ## &entity;
-    errors.add(errorMsg(x, "unknown entity: " & x.entityName))
+    result = newEntity(x.entityName)
     next(x)
   of xmlEof: discard
 
-proc parseXml*(s: Stream, filename: string, 
-               errors: var seq[string]): XmlNode = 
-  ## parses the XML from stream `s` and returns a ``PXmlNode``. Every
-  ## occurred parsing error is added to the `errors` sequence.
+proc parseXml*(s: Stream, filename: string,
+               errors: var seq[string], options: set[XmlParseOption] = {reportComments}): XmlNode =
+  ## Parses the XML from stream ``s`` and returns a ``XmlNode``. Every
+  ## occurred parsing error is added to the ``errors`` sequence.
   var x: XmlParser
-  open(x, s, filename, {reportComments})
+  open(x, s, filename, options)
   while true:
     x.next()
     case x.kind
-    of xmlElementOpen, xmlElementStart: 
+    of xmlElementOpen, xmlElementStart:
       result = parse(x, errors)
       break
     of xmlComment, xmlWhitespace, xmlSpecial, xmlPI: discard # just skip it
@@ -120,40 +121,56 @@ proc parseXml*(s: Stream, filename: string,
       break
   close(x)
 
-proc parseXml*(s: Stream): XmlNode = 
-  ## parses the XTML from stream `s` and returns a ``PXmlNode``. All parsing
-  ## errors are turned into an ``EInvalidXML`` exception.
+proc parseXml*(s: Stream, options: set[XmlParseOption] = {reportComments}): XmlNode =
+  ## Parses the XML from stream ``s`` and returns a ``XmlNode``. All parsing
+  ## errors are turned into an ``XmlError`` exception.
   var errors: seq[string] = @[]
-  result = parseXml(s, "unknown_html_doc", errors)
+  result = parseXml(s, "unknown_xml_doc", errors, options)
   if errors.len > 0: raiseInvalidXml(errors)
 
-proc loadXml*(path: string, errors: var seq[string]): XmlNode =
-  ## Loads and parses XML from file specified by ``path``, and returns 
-  ## a ``PXmlNode``. Every occurred parsing error is added to the `errors`
+proc parseXml*(str: string, options: set[XmlParseOption] = {reportComments}): XmlNode =
+  ## Parses the XML from string ``str`` and returns a ``XmlNode``. All parsing
+  ## errors are turned into an ``XmlError`` exception.
+  parseXml(newStringStream(str), options)
+
+proc loadXml*(path: string, errors: var seq[string], options: set[XmlParseOption] = {reportComments}): XmlNode =
+  ## Loads and parses XML from file specified by ``path``, and returns
+  ## a ``XmlNode``. Every occurred parsing error is added to the ``errors``
   ## sequence.
   var s = newFileStream(path, fmRead)
   if s == nil: raise newException(IOError, "Unable to read file: " & path)
-  result = parseXml(s, path, errors)
+  result = parseXml(s, path, errors, options)
 
-proc loadXml*(path: string): XmlNode =
-  ## Loads and parses XML from file specified by ``path``, and returns 
-  ## a ``PXmlNode``.  All parsing errors are turned into an ``EInvalidXML``
-  ## exception.  
+proc loadXml*(path: string, options: set[XmlParseOption] = {reportComments}): XmlNode =
+  ## Loads and parses XML from file specified by ``path``, and returns
+  ## a ``XmlNode``. All parsing errors are turned into an ``XmlError``
+  ## exception.
   var errors: seq[string] = @[]
-  result = loadXml(path, errors)
+  result = loadXml(path, errors, options)
   if errors.len > 0: raiseInvalidXml(errors)
 
 when isMainModule:
-  import os
-
-  var errors: seq[string] = @[]  
-  var x = loadXml(paramStr(1), errors)
-  for e in items(errors): echo e
-  
-  var f: File
-  if open(f, "xmltest.txt", fmWrite):
-    f.write($x)
-    f.close()
+  when not defined(testing):
+    import std/os
+
+    var errors: seq[string] = @[]
+    var x = loadXml(paramStr(1), errors)
+    for e in items(errors): echo e
+
+    var f: File
+    if open(f, "xmltest.txt", fmWrite):
+      f.write($x)
+      f.close()
+    else:
+      quit("cannot write test.txt")
   else:
-    quit("cannot write test.txt")
-    
+    block: # correctly parse ../../tests/testdata/doc1.xml
+      let filePath = "tests/testdata/doc1.xml"
+      var errors: seq[string] = @[]
+      var xml = loadXml(filePath, errors)
+      assert(errors.len == 0, "The file tests/testdata/doc1.xml should be parsed without errors.")
+
+    block bug1518:
+      var err: seq[string] = @[]
+      assert $parsexml(newStringStream"<tag>One &amp; two</tag>", "temp.xml",
+          err) == "<tag>One &amp; two</tag>"