XML with DOM
The klyn.io.xml.dom package parses XML into a document tree. DOM is convenient
when code needs random access, element lookup, tree edits, or serialization after updates.
Imports
import klyn.io
import klyn.io.xml.dom
import org.w3c.dom
Parse XML Text
DOMParser reads XML from a string, file path, FilePath, or
InputSource. The result is a DOMDocument whose
documentElement is the root element.
import klyn.io.xml.dom
import org.w3c.dom
xml = """
<catalog>
<book id="klyn">
<title>Klyn Guide</title>
</book>
</catalog>
"""
parser = DOMParser()
document as DOMDocument = parser.parseFromString(xml)
root as DOMElement = document.documentElement
books = root.getElementsByTagName("book")
first = books[0] as DOMElement
print(first.getAttribute("id"))
print(first.textContent.toTrim())
Parse Files
Use parseFromFile when the XML source lives on disk. Invalid XML raises
DOMException; filesystem errors raise IOException.
import klyn.io
import klyn.io.xml.dom
parser = DOMParser()
document = parser.parseFromFile(FilePath("catalog.xml"))
print(document.documentElement.tagName)
Build and Serialize
DOM can also create a document programmatically. Append elements and text nodes, then use
XMLSerializer to produce XML text.
import klyn.io.xml.dom
document = DOMDocument()
root = document.createElement("catalog")
document.appendChild(root)
book = document.createElement("book")
book.setAttribute("id", "klyn")
root.appendChild(book)
book.appendChild(document.createTextNode("Klyn Guide"))
print(XMLSerializer.serialize(document, prettyPrint=true, indent=2))
Safe Tree Mutations
A document accepts at most one root element and one document type, with the document type
before the root. Text nodes cannot have children. Invalid insertions or replacements raise
DOMException without changing either tree. Nodes from another document must
first be imported or adopted.
Inserting a DocumentFragment transfers its children in order and empties the
fragment; the fragment itself never becomes a child. The entire insertion is validated before
any transfer. replaceChild follows the same rules and returns the removed child.
import klyn.io.xml.dom
document = XMLDocument()
root = document.createElement("catalog")
document.appendChild(root)
fragment = document.createDocumentFragment()
fragment.appendChild(document.createElement("book"))
fragment.appendChild(document.createElement("magazine"))
root.appendChild(fragment)
assert root.childNodes.length == 2
assert fragment.childNodes.length == 0
assert fragment.parentNode is null
DOM vs SAX
DOM is easier to query and mutate, but it keeps the document tree in memory. For large files where you only need a streaming pass, prefer SAX. For configuration files, generated documents, and tree transformations, DOM is usually the simpler model.