--- name: processing-xml description: Creates, reads, modifies, validates, and queries XML files with Python. Use when the user asks to parse, edit, generate, validate, or extract data from an .xml file, mentions XML elements, attributes, namespaces, XPath queries, or XSD validation, or needs to transform XML data. Do not use for HTML pages (different parser tolerance) or for the internal XML of .docx/.xlsx/.pptx files (use the corresponding Office skill). --- # Processing XML ## When to use / when NOT to use - **Use for:** creating, reading, editing, validating, or querying standalone `.xml` files (data feeds, configs, sitemaps, SVG as data, exports). - **Do NOT use for:** HTML pages (use the HTML skill — HTML parsers tolerate malformed markup, XML parsers do not) or the internal XML inside `.docx`/`.xlsx`/`.pptx` archives (use the corresponding Office skill). ## Quick reference **Default:** stdlib `xml.etree.ElementTree` (no install). **Untrusted input:** `defusedxml` (`pip install defusedxml`) — same API, blocks entity-expansion attacks. **Escape hatch:** `lxml` (`pip install lxml`) only when you need full XPath 1.0, XSD validation, or pretty-printing on Python <3.9. ```python import xml.etree.ElementTree as ET # Read tree = ET.parse("data.xml") root = tree.getroot() # Query (namespaced documents need an explicit map) ns = {"a": "http://example.com/ns"} items = root.findall(".//a:item", ns) # Modify for item in items: item.set("status", "done") # Write — always preserve the declaration and encoding tree.write("data.xml", xml_declaration=True, encoding="utf-8") ``` **Create:** ```python root = ET.Element("catalog") book = ET.SubElement(root, "book", id="1") ET.SubElement(book, "title").text = "Example" ET.indent(root) # pretty-print, Python 3.9+ ET.ElementTree(root).write("out.xml", xml_declaration=True, encoding="utf-8") ``` ## Rules - **Never regex-edit XML.** Parse, modify the tree, re-serialize — always. - Handle namespaces explicitly with a namespace map; register prefixes before writing to avoid `ns0:` pollution. - Always write with `xml_declaration=True, encoding="utf-8"` so the declaration survives round-trips. ## Workflow 1. Identify the operation (create / read / modify / validate / query) and whether input is untrusted (→ defusedxml). 2. Parse the file; on `ET.ParseError`, report the message with its line/column verbatim and stop — do not guess at fixes. 3. Perform the operation per the Quick reference (deeper recipes in references/recipes.md). 4. Write with declaration + encoding preserved. 5. **Validate:** re-parse the written file (`ET.parse(output)`); if an XSD was given, validate against it with lxml. Fix and repeat step 3 until it parses clean. ## Edge cases & failure modes - **`lxml`/`defusedxml` missing** → `pip install lxml` / `pip install defusedxml`; fall back to stdlib ElementTree if the feature allows. - **Malformed XML** → relay the parser's error (line, column) to the user; never hand-patch text and retry silently. - **Encoding mismatch** (declaration says one thing, bytes say another) → parse from bytes, not decoded text; report if it still fails. - **Huge files (>100 MB)** → stream with `ET.iterparse(path, events=("end",))` and `elem.clear()` after each record instead of loading the whole tree. ## References Deeper copy-paste recipes (XPath, XSD validation, namespace round-trips, conversion): see [references/recipes.md](references/recipes.md).