SPB Git

spb/ultra-sharp-agent-skills Public

Ultra-Sharp Agent Skills — a research-first skill-authoring system + 72 production-ready skills for AI agents.

Python 100%

# XML Recipes

# Contents

  • Create a document with namespaces
  • Read and extract (XPath)
  • Modify: insert, remove, rename, move
  • Validate against an XSD
  • Streaming huge files
  • Convert XML ↔ dict/JSON
  • Gotchas

# Create a document with namespaces

python
import xml.etree.ElementTree as ET

NS = "http://example.com/catalog"
ET.register_namespace("", NS)  # default namespace, no prefix in output

root = ET.Element(f"{{{NS}}}catalog")
book = ET.SubElement(root, f"{{{NS}}}book", {"id": "bk101"})
ET.SubElement(book, f"{{{NS}}}title").text = "XML Developer's Guide"
ET.SubElement(book, f"{{{NS}}}price").text = "44.95"

ET.indent(root)                     # 2-space pretty print (3.9+)
ET.ElementTree(root).write("catalog.xml",
                           xml_declaration=True, encoding="utf-8")

# Read and extract (XPath)

ElementTree supports a subset of XPath — child paths, //, [@attr], [tag='text'], positional [1]:

python
tree = ET.parse("catalog.xml")
root = tree.getroot()
ns = {"c": "http://example.com/catalog"}

first = root.find("c:book[1]", ns)                    # first book
cheap = root.findall(".//c:book[c:price='44.95']", ns)
ids = [b.get("id") for b in root.findall(".//c:book", ns)]
text = root.findtext(".//c:book/c:title", default="", namespaces=ns)

Full XPath 1.0 (functions, contains(), axes) needs lxml:

python
from lxml import etree
root = etree.parse("catalog.xml").getroot()
titles = root.xpath("//c:book[contains(c:title,'Guide')]/c:title/text()",
                    namespaces={"c": "http://example.com/catalog"})

# Modify: insert, remove, rename, move

python
tree = ET.parse("catalog.xml")
root = tree.getroot()
ns = {"c": "http://example.com/catalog"}

# Insert after an existing child (ElementTree has no insert-after: use index)
books = root.findall("c:book", ns)
new = ET.Element(f"{{http://example.com/catalog}}book", {"id": "bk102"})
root.insert(list(root).index(books[-1]) + 1, new)

# Remove — you must remove from the PARENT
for bad in root.findall("c:book[@id='bk101']", ns):
    root.remove(bad)

# Rename a tag
for el in root.iter(f"{{http://example.com/catalog}}price"):
    el.tag = f"{{http://example.com/catalog}}cost"

tree.write("catalog.xml", xml_declaration=True, encoding="utf-8")

To find a parent when you only matched the child (stdlib has no getparent()):

python
parents = {c: p for p in root.iter() for c in p}
parents[child].remove(child)

# Validate against an XSD

Requires lxml (pip install lxml):

python
from lxml import etree

schema = etree.XMLSchema(etree.parse("catalog.xsd"))
doc = etree.parse("catalog.xml")
if not schema.validate(doc):
    for err in schema.error_log:
        print(f"line {err.line}, col {err.column}: {err.message}")

Report every error with line/column; fix the tree, re-serialize, re-validate.

# Streaming huge files

Load-then-clear keeps memory flat regardless of file size:

python
import xml.etree.ElementTree as ET

for event, elem in ET.iterparse("huge.xml", events=("end",)):
    if elem.tag.endswith("record"):
        process(elem)
        elem.clear()   # release children; keeps memory bounded

# Convert XML ↔ dict/JSON

No stdlib one-liner exists; for flat, repetitive data write it explicitly:

python
rows = [{"id": b.get("id"), "title": b.findtext("c:title", "", ns)}
        for b in root.findall(".//c:book", ns)]
import json; json.dump(rows, open("books.json", "w"), indent=2)

For arbitrary nesting, pip install xmltodict and xmltodict.parse(open("f.xml", "rb")) — but beware: single children become dicts, repeated children become lists, so downstream code must handle both shapes.

# Gotchas

  • ns0: prefix pollution. ElementTree invents ns0: prefixes on write unless you call ET.register_namespace(prefix, uri) before parsing/writing. Register "" for a default namespace.
  • Truthiness trap. An element with no children is falsy: if elem: is False even when the element exists. Always use if elem is not None:.
  • find() vs findall() with no namespace map silently return nothing on namespaced documents — the tag you search must be {uri}tag or use the ns map. "It finds nothing" almost always means a missing namespace map.
  • No parent pointers in stdlib ElementTree — removal requires the parent (see recipe above); lxml elements have .getparent().
  • Comments and processing instructions are dropped by the default ElementTree parser. If they must survive a round-trip, use lxml, which preserves them.
  • ET.tostring() omits the XML declaration unless xml_declaration=True — and returns bytes when an encoding is given.
  • Entity attacks (billion laughs, external entities). Never parse untrusted XML with plain ElementTree/lxml defaults; use defusedxml drop-ins (defusedxml.ElementTree.parse).
  • ET.indent() mutates text nodes — don't use it on documents where whitespace inside elements is significant (mixed content).