When working with XML-based systems, you often need to inject, modify, or restructure XML documents dynamically at runtime. Whether you're building configuration files, templating UI views (e.g., Odoo), transforming API payloads, or manipulating document structures, lxml is one of Python’s most powerful tools for the job.
This guide walks you through the concepts, the pitfalls, and practical examples of dynamic XML injection using lxml.
Why Use lxml for Dynamic XML Injection
Python’s built-in xml.etree.ElementTree is good for simple tasks, but lxml offers major advantages:
- Full XPath support
- Supports XSLT
- Sane handling of namespaces
- More powerful insertion and modification API
- Cleaner manipulation of existing nodes
- Much faster in many cases
When XML structure becomes complex or dynamic, lxml gives you fine-grained control.
Core Concepts of XML Injection with lxml
Dynamic XML injection simply means programmatically inserting new nodes into an existing XML document based on conditions at runtime.
You'll use four core operations:
- Parsing (read or create XML)
- Searching (using XPath)
- Insertion (append, insert before/after)
- Modification (attributes, text, structure)
Let’s walk through examples.
1. Parsing and Creating XML
from lxml import etree
xml = """
<root>
<items>
<item id="1">A</item>
<item id="2">B</item>
</items>
</root>
"""
tree = etree.fromstring(xml)
2. Injecting New Nodes Dynamically
items_node = tree.xpath("//items")[0]
new_item = etree.Element("item", id="3")
new_item.text = "C"
items_node.append(new_item)
3. Insert Before/After a Specific Node
target = tree.xpath("//item[@id='2']")[0]
new_node = etree.Element("item", id="1.5")
new_node.text = "Injected Before ID 2"
target.addprevious(new_node)
or after
target.addnext(new_node)
4. Modify Attributes or Text Dynamically
node = tree.xpath("//item[@id='1']")[0]
node.set("status", "updated")
node.text = "Updated Value"
5. Conditional / Rule Based Injection
for item in tree.xpath("//item"):
if int(item.get("id")) % 2 == 0:
extra = etree.Element("meta")
extra.text = "Even"
item.append(extra)
