src/fusion/htmlparser/xmltree

Search:
Group by:

A simple XML tree generator.

import xmltree

var g = newElement("myTag")
g.add newText("some text")
g.add newComment("this is comment")

var h = newElement("secondTag")
h.add newEntity("some entity")

let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes
let k = newXmlTree("treeTag", [g, h], att)

echo k
# <treeTag key2="second value" key1="first value">
#   <myTag>some text<!-- this is comment --></myTag>
#   <secondTag>&some entity;</secondTag>
# </treeTag>

See also:

Types

XmlAttributes = StringTableRef

An alias for a string to string mapping.

Use toXmlAttributes proc to create XmlAttributes.

XmlNode = ref XmlNodeObj

An XML tree consisting of XML nodes.

Use newXmlTree proc for creating a new tree.

XmlNodeKind = enum
  xnText,                   ## a text element
  xnVerbatimText, xnElement, ## an element with 0 or more children
  xnCData,                  ## a CDATA node
  xnEntity,                 ## an entity (like ``&thing;``)
  xnComment                  ## an XML comment
Different kinds of XML nodes.

Consts

xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
Header to use for complete XML output.

Procs

proc `$`(n: XmlNode): string {....raises: [], tags: [], forbids: [].}

Converts n into its string representation.

No <$xml ...$> declaration is produced, so that the produced XML fragments are composable.

proc `[]`(n: var XmlNode; i: int): var XmlNode {.inline, ...raises: [], tags: [],
    forbids: [].}
Returns the i'th child of n so that it can be modified.
proc `[]`(n: XmlNode; i: int): XmlNode {.inline, ...raises: [], tags: [],
    forbids: [].}
Returns the i'th child of n.

Example:

var f = newElement("myTag")
f.add newElement("first")
f.insert(newElement("second"), 0)
assert $f[1] == "<first>\n</first>"
assert $f[0] == "<second>\n</second>"
proc add(father, son: XmlNode) {.inline, ...raises: [], tags: [], forbids: [].}

Adds the child son to father.

See also:

Example:

var f = newElement("myTag")
f.add newText("my text")
f.add newElement("sonTag")
f.add newEntity("my entity")
assert $f == "<myTag>my text<sonTag></sonTag>&my entity;</myTag>"
proc add(result: var string; n: XmlNode; indent = 0; indWidth = 2;
         addNewLines = true) {....raises: [], tags: [], forbids: [].}
Adds the textual representation of n to string result.

Example:

var
  a = newElement("firstTag")
  b = newText("my text")
  c = newComment("my comment")
  s = ""
s.add(c)
a.add(b)
s.add(a)
assert s == "<!-- my comment --><firstTag>my text</firstTag>"
proc addEscaped(result: var string; s: string) {....raises: [], tags: [],
    forbids: [].}
The same as result.add(escape(s)), but more efficient.
proc attr(n: XmlNode; name: string): string {....raises: [], tags: [], forbids: [].}

Finds the first attribute of n with a name of name. Returns "" on failure.

See also:

Example:

var j = newElement("myTag")
let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes
j.attrs = att
assert j.attr("key1") == "first value"
assert j.attr("key2") == "second value"
proc attrs(n: XmlNode): XmlAttributes {.inline, ...raises: [], tags: [],
                                        forbids: [].}

Gets the attributes belonging to n.

Returns nil if attributes have not been initialised for this node.

See also:

Example:

var j = newElement("myTag")
assert j.attrs == nil
let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes
j.attrs = att
assert j.attrs == att
proc attrs=(n: XmlNode; attr: XmlAttributes) {.inline, ...raises: [], tags: [],
    forbids: [].}

Sets the attributes belonging to n.

See also:

Example:

var j = newElement("myTag")
assert j.attrs == nil
let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes
j.attrs = att
assert j.attrs == att
proc attrsLen(n: XmlNode): int {.inline, ...raises: [], tags: [], forbids: [].}

Returns the number of n's attributes.

See also:

Example:

var j = newElement("myTag")
assert j.attrsLen == 0
let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes
j.attrs = att
assert j.attrsLen == 2
proc child(n: XmlNode; name: string): XmlNode {....raises: [], tags: [],
    forbids: [].}
Finds the first child element of n with a name of name. Returns nil on failure.

Example:

var f = newElement("myTag")
f.add newElement("firstSon")
f.add newElement("secondSon")
f.add newElement("thirdSon")
assert $(f.child("secondSon")) == "<secondSon>\n</secondSon>"
proc clear(n: var XmlNode) {....raises: [], tags: [], forbids: [].}
Recursively clear all children of an XmlNode.
var g = newElement("myTag")
g.add newText("some text")
g.add newComment("this is comment")

var h = newElement("secondTag")
h.add newEntity("some entity")

let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes
var k = newXmlTree("treeTag", [g, h], att)

echo k
## <treeTag key2="second value" key1="first value">
##   <myTag>some text<!-- this is comment --></myTag>
##   <secondTag>&some entity;</secondTag>
## </treeTag>

clear(k)
echo k
## <treeTag key2="second value" key1="first value" />
proc clientData(n: XmlNode): int {.inline, ...raises: [], tags: [], forbids: [].}

Gets the client data of n.

The client data field is used by the HTML parser and generator.

proc clientData=(n: XmlNode; data: int) {.inline, ...raises: [], tags: [],
    forbids: [].}

Sets the client data of n.

The client data field is used by the HTML parser and generator.

proc delete(n: XmlNode; i: Natural) {.noSideEffect, ...raises: [], tags: [],
                                      forbids: [].}

Delete the i'th child of n.

See also:

Example:

var f = newElement("myTag")
f.add newElement("first")
f.insert(newElement("second"), 0)
f.delete(0)
assert $f == """<myTag>
  <first>
  </first>
</myTag>"""
proc escape(s: string): string {....raises: [], tags: [], forbids: [].}

Escapes s for inclusion into an XML document.

Escapes these characters:

charis converted to
<&lt;
>&gt;
&&amp;
"&quot;
'&apos;

You can also use addEscaped proc.

proc findAll(n: XmlNode; tag: string; caseInsensitive = false): seq[XmlNode] {.
    ...raises: [], tags: [], forbids: [].}
A shortcut version to assign in let blocks.

Example:

var
  b = newElement("good")
  c = newElement("bad")
  d = newElement("BAD")
  e = newElement("GOOD")
b.add newText("b text")
c.add newText("c text")
d.add newText("d text")
e.add newText("e text")
let a = newXmlTree("father", [b, c, d, e])
assert $(a.findAll("good")) == "@[<good>b text</good>]"
assert $(a.findAll("BAD")) == "@[<BAD>d text</BAD>]"
assert $(a.findAll("good", caseInsensitive = true)) == "@[<good>b text</good>, <GOOD>e text</GOOD>]"
assert $(a.findAll("BAD", caseInsensitive = true)) == "@[<bad>c text</bad>, <BAD>d text</BAD>]"
proc findAll(n: XmlNode; tag: string; result: var seq[XmlNode];
             caseInsensitive = false) {....raises: [], tags: [], forbids: [].}

Iterates over all the children of n returning those matching tag.

Found nodes satisfying the condition will be appended to the result sequence.

Example:

var
  b = newElement("good")
  c = newElement("bad")
  d = newElement("BAD")
  e = newElement("GOOD")
b.add newText("b text")
c.add newText("c text")
d.add newText("d text")
e.add newText("e text")
let a = newXmlTree("father", [b, c, d, e])
var s = newSeq[XmlNode]()
a.findAll("good", s)
assert $s == "@[<good>b text</good>]"
s.setLen(0)
a.findAll("good", s, caseInsensitive = true)
assert $s == "@[<good>b text</good>, <GOOD>e text</GOOD>]"
s.setLen(0)
a.findAll("BAD", s)
assert $s == "@[<BAD>d text</BAD>]"
s.setLen(0)
a.findAll("BAD", s, caseInsensitive = true)
assert $s == "@[<bad>c text</bad>, <BAD>d text</BAD>]"
proc innerText(n: XmlNode): string {....raises: [], tags: [], forbids: [].}
Gets the inner text of n:
  • If n is xnText or xnEntity, returns its content.
  • If n is xnElement, runs recursively on each child node and concatenates the results.
  • Otherwise returns an empty string.

See also:

Example:

var f = newElement("myTag")
f.add newText("my text")
f.add newComment("my comment")
f.add newEntity("my entity")
assert $f == "<myTag>my text<!-- my comment -->&my entity;</myTag>"
assert innerText(f) == "my textmy entity"
proc insert(father, son: XmlNode; index: int) {.inline, ...raises: [], tags: [],
    forbids: [].}

Insert the child son to a given position in father.

father and son must be of xnElement kind.

See also:

Example:

var f = newElement("myTag")
f.add newElement("first")
f.insert(newElement("second"), 0)
assert $f == """<myTag>
  <second>
  </second>
  <first>
  </first>
</myTag>"""
proc kind(n: XmlNode): XmlNodeKind {.inline, ...raises: [], tags: [], forbids: [].}
Returns n's kind.

Example:

var a = newElement("firstTag")
assert a.kind == xnElement
var b = newText("my text")
assert b.kind == xnText
proc len(n: XmlNode): int {.inline, ...raises: [], tags: [], forbids: [].}
Returns the number of n's children.

Example:

var f = newElement("myTag")
f.add newElement("first")
f.insert(newElement("second"), 0)
assert len(f) == 2
proc newCData(cdata: string): XmlNode {....raises: [], tags: [], forbids: [].}
Creates a new XmlNode of kind xnCData with the text cdata.

Example:

var d = newCData("my cdata")
assert d.kind == xnCData
assert $d == "<![CDATA[my cdata]]>"
proc newComment(comment: string): XmlNode {....raises: [], tags: [], forbids: [].}
Creates a new XmlNode of kind xnComment with the text comment.

Example:

var c = newComment("my comment")
assert c.kind == xnComment
assert $c == "<!-- my comment -->"
proc newElement(tag: string): XmlNode {....raises: [], tags: [], forbids: [].}

Creates a new XmlNode of kind xnElement with the given tag.

See also:

Example:

var a = newElement("firstTag")
a.add newElement("childTag")
assert a.kind == xnElement
assert $a == """<firstTag>
  <childTag>
  </childTag>
</firstTag>"""
proc newEntity(entity: string): XmlNode {....raises: [], tags: [], forbids: [].}
Creates a new XmlNode of kind xnEntity with the text entity.

Example:

var e = newEntity("my entity")
assert e.kind == xnEntity
assert $e == "&my entity;"
proc newText(text: string): XmlNode {....raises: [], tags: [], forbids: [].}
Creates a new XmlNode of kind xnText with the text text.

Example:

var b = newText("my text")
assert b.kind == xnText
assert $b == "my text"
proc newVerbatimText(text: string): XmlNode {....raises: [], tags: [], forbids: [].}
Creates a new XmlNode of kind xnVerbatimText with the text text. Since: Version 1.3.
proc newXmlTree(tag: string; children: openArray[XmlNode];
                attributes: XmlAttributes = nil): XmlNode {....raises: [],
    tags: [], forbids: [].}

Creates a new XML tree with tag, children and attributes.

See also:

var g = newElement("myTag")
g.add newText("some text")
g.add newComment("this is comment")
var h = newElement("secondTag")
h.add newEntity("some entity")
let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes
let k = newXmlTree("treeTag", [g, h], att)

echo k
## <treeTag key2="second value" key1="first value">
##   <myTag>some text<!-- this is comment --></myTag>
##   <secondTag>&some entity;</secondTag>
## </treeTag>
proc rawTag(n: XmlNode): string {.inline, ...raises: [], tags: [], forbids: [].}

Returns the underlying 'tag' string by reference.

This is only used for speed hacks.

proc rawText(n: XmlNode): string {.inline, ...raises: [], tags: [], forbids: [].}

Returns the underlying 'text' string by reference.

This is only used for speed hacks.

proc tag(n: XmlNode): string {.inline, ...raises: [], tags: [], forbids: [].}

Gets the tag name of n.

n has to be an xnElement node.

See also:

Example:

var a = newElement("firstTag")
a.add newElement("childTag")
assert $a == """<firstTag>
  <childTag>
  </childTag>
</firstTag>"""
assert a.tag == "firstTag"
proc tag=(n: XmlNode; tag: string) {.inline, ...raises: [], tags: [], forbids: [].}

Sets the tag name of n.

n has to be an xnElement node.

See also:

Example:

var a = newElement("firstTag")
a.add newElement("childTag")
assert $a == """<firstTag>
  <childTag>
  </childTag>
</firstTag>"""
a.tag = "newTag"
assert $a == """<newTag>
  <childTag>
  </childTag>
</newTag>"""
proc text(n: XmlNode): string {.inline, ...raises: [], tags: [], forbids: [].}

Gets the associated text with the node n.

n can be a CDATA, Text, comment, or entity node.

See also:

Example:

var c = newComment("my comment")
assert $c == "<!-- my comment -->"
assert c.text == "my comment"
proc text=(n: XmlNode; text: string) {.inline, ...raises: [], tags: [], forbids: [].}

Sets the associated text with the node n.

n can be a CDATA, Text, comment, or entity node.

See also:

Example:

var e = newEntity("my entity")
assert $e == "&my entity;"
e.text = "a new entity text"
assert $e == "&a new entity text;"
proc toXmlAttributes(keyValuePairs: varargs[tuple[key, val: string]]): XmlAttributes {.
    ...raises: [], tags: [], forbids: [].}
Converts {key: value} pairs into XmlAttributes.
let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes
var j = newElement("myTag")
j.attrs = att

echo j
## <myTag key2="second value" key1="first value" />

Iterators

iterator items(n: XmlNode): XmlNode {.inline, ...raises: [], tags: [], forbids: [].}

Iterates over all direct children of n.

Examples:

var g = newElement("myTag")
g.add newText("some text")
g.add newComment("this is comment")

var h = newElement("secondTag")
h.add newEntity("some entity")
g.add h

assert $g == "<myTag>some text<!-- this is comment --><secondTag>&some entity;</secondTag></myTag>"
for x in g: # the same as `for x in items(g):`
  echo x

# some text
# <!-- this is comment -->
# <secondTag>&some entity;<![CDATA[some cdata]]></secondTag>
iterator mitems(n: var XmlNode): var XmlNode {.inline, ...raises: [], tags: [],
    forbids: [].}
Iterates over all direct children of n so that they can be modified.

Macros

macro `<>`(x: untyped): untyped
Constructor macro for XML. Example usage:
<>a(href="http://nim-lang.org", newText("Nim rules."))

Produces an XML tree for::

<a href="http://nim-lang.org">Nim rules.</a>