☰

# std/xmltree

Theme:

- Manual
- Standard library
- Index
- Compiler docs
- Fusion docs
- devel, stable

Search:
Source Edit

A simple XML tree generator.

Example:

    import std/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)

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

See also:

- xmlparser module for high-level XML parsing
- parsexml module for low-level XML parsing
- htmlgen module for html code generator

# Imports

since, macros, strtabs, strutils, sequtils, assertions

# Types

    XmlAttributes = StringTableRef

  An alias for a string to string mapping.

  Use toXmlAttributes proc to create `XmlAttributes`.

  Source Edit

    XmlNode = ref XmlNodeObj

  An XML tree consisting of XML nodes.

  Use newXmlTree proc for creating a new tree.

  Source Edit

    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. Source Edit

# Consts

    xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"

  Header to use for complete XML output. Source Edit

# 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.

  Source Edit

    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. Source Edit

    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 />"
      assert $f[0] == "<second />"

  Source Edit

    proc add(father, son: XmlNode) {.inline, ...raises: [], tags: [], forbids: [].}

  Adds the child `son` to `father`. `father` must be of `xnElement` type

  See also:

  - add proc
  - insert proc
  - insert proc
  - delete proc
  - delete proc
  - replace proc
  - replace proc

  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 />&my entity;</myTag>"

  Source Edit

    proc add(father: XmlNode; sons: openArray[XmlNode]) {.inline, ...raises: [],
        tags: [], forbids: [].}

  Adds the children `sons` to `father`. `father` must be of `xnElement` type

  See also:

  - add proc
  - insert proc
  - insert proc
  - delete proc
  - delete proc
  - replace proc
  - replace proc

  Example:

      var f = newElement("myTag")
      f.add(@[newText("my text"), newElement("sonTag"), newEntity("my entity")])
      assert $f == "<myTag>my text<sonTag />&my entity;</myTag>"

  Source Edit

    proc add(result: var string; n: XmlNode; indent = 0; indWidth = 2;
             addNewLines = true) {.inline, ...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)
      s.add(a)
      s.add(b)
      assert s == "<!-- my comment --><firstTag />my text"

  Source Edit

    proc addEscaped(result: var string; s: string) {....raises: [], tags: [],
        forbids: [].}

  The same as result.add(escape(s)), but more efficient. Source Edit

    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:

  - attrs proc for XmlAttributes getter
  - attrs= proc for XmlAttributes setter
  - attrsLen proc for number of attributes

  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"

  Source Edit

    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:

  - attrs= proc for XmlAttributes setter
  - attrsLen proc for number of attributes
  - attr proc for finding an attribute

  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

  Source Edit

    proc attrs=(n: XmlNode; attr: XmlAttributes) {.inline, ...raises: [], tags: [],
        forbids: [].}

  Sets the attributes belonging to `n`.

  See also:

  - attrs proc for XmlAttributes getter
  - attrsLen proc for number of attributes
  - attr proc for finding an attribute

  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

  Source Edit

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

  Returns the number of `n`'s attributes.

  See also:

  - attrs proc for XmlAttributes getter
  - attrs= proc for XmlAttributes setter
  - attr proc for finding an attribute

  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

  Source Edit

    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 />"

  Source Edit

    proc clear(n: var XmlNode) {....raises: [], tags: [], forbids: [].}

  Recursively clears all children of an XmlNode.

  Example:

      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)

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

      clear(k)
      doAssert $k == """<treeTag key1="first value" key2="second value" />"""

  Source Edit

    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.

  Source Edit

    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.

  Source Edit

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

  Deletes the `i`'th child of `n`.

  See also:

  - delete proc
  - add proc
  - add proc
  - insert proc
  - insert proc
  - replace proc
  - replace proc

  Example:

      var f = newElement("myTag")
      f.add newElement("first")
      f.insert(newElement("second"), 0)
      f.delete(0)
      assert $f == """<myTag>
        <first />
      </myTag>"""

  Source Edit

    proc delete(n: XmlNode; slice: Slice[int]) {....raises: [], tags: [], forbids: [].}

  Deletes the items `n[slice]` of `n`.

  See also:

  - delete proc
  - add proc
  - add proc
  - insert proc
  - insert proc
  - replace proc
  - replace proc

  Example:

      var f = newElement("myTag")
      f.add newElement("first")
      f.insert([newElement("second"), newElement("third")], 0)
      f.delete(0..1)
      assert $f == """<myTag>
        <first />
      </myTag>"""

  Source Edit

    proc escape(s: string): string {....raises: [], tags: [], forbids: [].}

  Escapes `s` for inclusion into an XML document.

  Escapes these characters:

  char | is converted to
  --- | ---
  `<` | `&lt;`
  `>` | `&gt;`
  `&` | `&amp;`
  `"` | `&quot;`
  `'` | `&apos;`

  You can also use addEscaped proc.

  Source Edit

    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>]"

  Source Edit

    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>]"

  Source Edit

    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:

  - text proc

  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"

  Source Edit

    proc insert(father, son: XmlNode; index: int) {.inline, ...raises: [], tags: [],
        forbids: [].}

  Inserts the child `son` to a given position in `father`.

  `father` must be of `xnElement` kind.

  See also:

  - insert proc
  - add proc
  - add proc
  - delete proc
  - delete proc
  - replace proc
  - replace proc

  Example:

      var f = newElement("myTag")
      f.add newElement("first")
      f.insert(newElement("second"), 0)
      assert $f == """<myTag>
        <second />
        <first />
      </myTag>"""

  Source Edit

    proc insert(father: XmlNode; sons: openArray[XmlNode]; index: int) {.inline,
        ...raises: [], tags: [], forbids: [].}

  Inserts the children openArray`sons` to a given position in `father`.

  `father` must be of `xnElement` kind.

  See also:

  - insert proc
  - add proc
  - add proc
  - delete proc
  - delete proc
  - replace proc
  - replace proc

  Example:

      var f = newElement("myTag")
      f.add newElement("first")
      f.insert([newElement("second"), newElement("third")], 0)
      assert $f == """<myTag>
        <second />
        <third />
        <first />
      </myTag>"""

  Source Edit

    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

  Source Edit

    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

  Source Edit

    proc newCData(cdata: sink 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]]>"

  Source Edit

    proc newComment(comment: sink 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 -->"

  Source Edit

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

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

  See also:

  - newXmlTree proc
  - <> macro

  Example:

      var a = newElement("firstTag")
      a.add newElement("childTag")
      assert a.kind == xnElement
      assert $a == """<firstTag>
        <childTag />
      </firstTag>"""

  Source Edit

    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;"

  Source Edit

    proc newText(text: sink 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"

  Source Edit

    proc newVerbatimText(text: sink string): XmlNode {....raises: [], tags: [],
        forbids: [].}

  Creates a new `XmlNode` of kind `xnVerbatimText` with the text `text`. Since: Version 1.3. Source Edit

    proc newXmlTree(tag: sink string; children: openArray[XmlNode];
                    attributes: XmlAttributes = nil): XmlNode {....raises: [],
        tags: [], forbids: [].}

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

  See also:

  - newElement proc
  - <> macro

  Example:

      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)

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

  Source Edit

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

  Returns the underlying 'tag' string by reference.

  This is only used for speed hacks.

  Source Edit

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

  Returns the underlying 'text' string by reference.

  This is only used for speed hacks.

  Source Edit

    proc replace(n: XmlNode; i: Natural; replacement: openArray[XmlNode]) {.
        ...raises: [], tags: [], forbids: [].}

  Replaces the `i`'th child of `n` with `replacement` openArray.

  `n` must be of `xnElement` kind.

  See also:

  - replace proc
  - add proc
  - add proc
  - delete proc
  - delete proc
  - insert proc
  - insert proc

  Example:

      var f = newElement("myTag")
      f.add newElement("first")
      f.insert(newElement("second"), 0)
      f.replace(0, @[newElement("third"), newElement("fourth")])
      assert $f == """<myTag>
        <third />
        <fourth />
        <first />
      </myTag>"""

  Source Edit

    proc replace(n: XmlNode; slice: Slice[int]; replacement: openArray[XmlNode]) {.
        ...raises: [], tags: [], forbids: [].}

  Deletes the items `n[slice]` of `n`.

  `n` must be of `xnElement` kind.

  See also:

  - replace proc
  - add proc
  - add proc
  - delete proc
  - delete proc
  - insert proc
  - insert proc

  Example:

      var f = newElement("myTag")
      f.add newElement("first")
      f.insert([newElement("second"), newElement("fifth")], 0)
      f.replace(0..1, @[newElement("third"), newElement("fourth")])
      assert $f == """<myTag>
        <third />
        <fourth />
        <first />
      </myTag>"""

  Source Edit

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

  Gets the tag name of `n`.

  `n` has to be an `xnElement` node.

  See also:

  - text proc for text getter
  - text= proc for text setter
  - tag= proc for tag setter
  - innerText proc

  Example:

      var a = newElement("firstTag")
      a.add newElement("childTag")
      assert $a == """<firstTag>
        <childTag />
      </firstTag>"""
      assert a.tag == "firstTag"

  Source Edit

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

  Sets the tag name of `n`.

  `n` has to be an `xnElement` node.

  See also:

  - text proc for text getter
  - text= proc for text setter
  - tag proc for tag getter

  Example:

      var a = newElement("firstTag")
      a.add newElement("childTag")
      assert $a == """<firstTag>
        <childTag />
      </firstTag>"""
      a.tag = "newTag"
      assert $a == """<newTag>
        <childTag />
      </newTag>"""

  Source Edit

    proc text(n: XmlNode): lent 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:

  - text= proc for text setter
  - tag proc for tag getter
  - tag= proc for tag setter
  - innerText proc

  Example:

      var c = newComment("my comment")
      assert $c == "<!-- my comment -->"
      assert c.text == "my comment"

  Source Edit

    proc text=(n: XmlNode; text: sink 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:

  - text proc for text getter
  - tag proc for tag getter
  - tag= proc for tag setter

  Example:

      var e = newEntity("my entity")
      assert $e == "&my entity;"
      e.text = "a new entity text"
      assert $e == "&a new entity text;"

  Source Edit

    proc toXmlAttributes(keyValuePairs: varargs[tuple[key, val: string]]): XmlAttributes {.
        ...raises: [], tags: [], forbids: [].}

  Converts `{key: value}` pairs into `XmlAttributes`.

  Example:

      let att = {"key1": "first value", "key2": "second value"}.toXmlAttributes
      var j = newElement("myTag")
      j.attrs = att

      doAssert $j == """<myTag key1="first value" key2="second value" />"""

  Source Edit

# Iterators

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

  Iterates over all direct children of `n`.

  Example:

      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>

  Source Edit

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

  Iterates over all direct children of `n` so that they can be modified. Source Edit

# Macros

    macro `<>`(x: untyped): untyped

  Constructor macro for XML. Example usage:

      <>a(href="https://nim-lang.org", newText("Nim rules."))

  Produces an XML tree for:

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

  Source Edit