Post

Handling XML with Python

Handling XML with Python

Why Should Network Engineers Care About XML?

In today’s world of APIs and structured data, XML (eXtensible Markup Language) may not be as hyped as JSON, but it’s still deeply embedded in network automation and device management. From NETCONF and RESTCONF to vendor-specific device outputs, XML is everywhere in the networking world.

Even though JSON is now dominant in modern APIs, XML still powers key infrastructure under the hood — especially in:

  • NETCONF (RFC 6241) — relies heavily on XML for structured configuration and operational data.
  • YANG models — data modeled in YANG often gets serialized as XML in NETCONF.
  • SOAP APIs — older but still active APIs for NMS and OSS tools.
  • CLI outputs from network devices — XML-formatted CLI outputs (e.g., show interfaces | display xml on Juniper).

So, being fluent in XML parsing and manipulation is critical when building automation workflows or network audits.


XML 101: A Quick Primer

Here’s what XML looks like:

1
2
3
4
5
6
7
8
<interface>
  <name>GigabitEthernet0/1</name>
  <status>up</status>
  <ip>
    <address>192.168.1.1</address>
    <netmask>255.255.255.0</netmask>
  </ip>
</interface>

Unlike JSON, XML uses nested tags and supports attributes, like this:

1
2
3
<interface name="GigabitEthernet0/1" status="up">
  <ip address="192.168.1.1" netmask="255.255.255.0"/>
</interface>

Key Concepts:

  • Elements<tag>value</tag>
  • Attributes<tag attribute="value" />
  • Namespaces – Used to avoid naming conflicts, especially in NETCONF.
  • Well-formed vs. Valid XML – XML must follow structure rules (well-formed) and may optionally conform to a schema (valid).

Real-World XML in Networking

Here’s an example snippet from a NETCONF response:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <data>
    <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
      <interface>
        <name>GigabitEthernet0/0</name>
        <enabled>true</enabled>
        <ipv4>
          <address>
            <ip>192.0.2.1</ip>
            <netmask>255.255.255.0</netmask>
          </address>
        </ipv4>
      </interface>
    </interfaces>
  </data>
</rpc-reply>

Parsing XML with Python

Python has built-in and third-party libraries to handle XML. Let’s explore a few ways to parse and navigate XML as a network engineer.

1. xml.etree.ElementTree – Built-in & Simple

1
2
3
4
5
6
7
import xml.etree.ElementTree as ET

xml_data = """<interface><name>Gig0/1</name><status>up</status></interface>"""
root = ET.fromstring(xml_data)

print(root.find('name').text)       # Output: Gig0/1
print(root.find('status').text)     # Output: up

Use when the XML is simple and predictable. Limited namespace support.

2. Handling NETCONF XML with Namespaces

When using NETCONF, namespaces are always involved. You must specify them explicitly.

1
2
3
4
5
6
7
8
9
10
ns = {
    'if': 'urn:ietf:params:xml:ns:yang:ietf-interfaces'
}

tree = ET.ElementTree(ET.fromstring(xml_with_namespace))
interfaces = tree.findall('.//if:interface', ns)

for intf in interfaces:
    name = intf.find('if:name', ns).text
    print(f"Interface: {name}")

Tip: Always map namespaces to prefixes and use those in your XPath queries.

3. lxml – More Power and XPath Support

1
2
3
4
5
from lxml import etree

tree = etree.fromstring(xml_data.encode())
names = tree.xpath('//interface/name/text()')
print(names)

Use lxml when dealing with complex XML, XPath queries, or schema validation.


Use Case: Extracting Interfaces from a NETCONF Response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from ncclient import manager
import xml.etree.ElementTree as ET

device = {
    "host": "10.0.0.1",
    "port": 830,
    "username": "admin",
    "password": "admin",
    "hostkey_verify": False
}

with manager.connect(**device) as m:
    filter = """
    <filter>
      <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"/>
    </filter>
    """
    response = m.get(filter)
    xml_data = response.data_xml

    ns = {'if': 'urn:ietf:params:xml:ns:yang:ietf-interfaces'}
    root = ET.fromstring(xml_data)
    for intf in root.findall('.//if:interface', ns):
        name = intf.find('if:name', ns).text
        print(f"Interface: {name}")

Bonus: Convert XML to JSON

Sometimes you need to convert XML to JSON for easier processing or integration.

1
2
3
4
5
6
7
import xmltodict
import json

xml_data = """<interface><name>Gig0/1</name><status>up</status></interface>"""
parsed = xmltodict.parse(xml_data)
json_data = json.dumps(parsed, indent=2)
print(json_data)

xmltodict is perfect for converting XML into Python dictionaries fast.

This post is licensed under CC BY 4.0 by the author.