XML (eXtensible Markup Language) is a text format for storing and transmitting structured data as a tree. It underpins product feeds from marketplaces and aggregators, banking and exchange formats, configuration files, and derivative formats — RSS feeds and sitemaps. This article is part of our broader overview of document parsing, focused specifically on XML parsing.
What is XML parsing, and how XML is structured
XML parsing is the process of reading an XML document and turning its text into a structured tree your code can navigate. An XML document is a tree of elements. Every element has a name (the tag), and may carry a set of attributes, text content, and nested elements.
<catalog>
<product id="101" available="true">
<name>Coffee grinder</name>
<price currency="USD">34.90</price>
</product>
<product id="102" available="false">
<name>Kettle</name>
<price currency="USD">21.90</price>
</product>
</catalog>
The key difference from JSON is that XML stores data in two places at once — in the text of elements (<name>Coffee grinder</name>) and in attributes (id="101"). Keep this in mind: when extracting, you'll reach sometimes for a tag's content, sometimes for its attributes.
A topic of its own is namespaces. In complex formats, tags look like <g:price> or <atom:link>, where the prefix is bound to a URI. Parsers require you to account for the namespace when searching for nodes — otherwise a query returns nothing. This is the single most common cause of "the parser finds nothing even though the data is right there."
Two approaches: tree in memory vs streaming
There are two fundamentally different ways to parse. The DOM approach builds the whole tree in memory and gives convenient navigation, including XPath — it's simple and fine for files up to tens of megabytes. The streaming approach (SAX / iterparse) reads the file event by event without loading it whole, and is indispensable for feeds hundreds of megabytes to gigabytes in size. For typical jobs, DOM is almost always enough; you switch to streaming when the file stops fitting in memory.
Python
The standard library includes the xml.etree.ElementTree module — enough for simple cases and requiring no installation.
import xml.etree.ElementTree as ET
tree = ET.parse("catalog.xml")
root = tree.getroot()
for product in root.findall("product"):
name = product.find("name").text
price = product.find("price").text
available = product.get("available") # reading an attribute
print(name, price, available)
For serious work, use lxml — it's faster, digests "dirty" XML better, and fully supports XPath, including namespaces.
from lxml import etree
tree = etree.parse("catalog.xml")
# XPath: every in-stock product
for product in tree.xpath("//product[@available='true']"):
name = product.xpath("string(name)")
price = product.xpath("string(price)")
print(name, price)
If the data arrives from an API as XML but you'd rather work with it like a dictionary, xmltodict turns XML into ordinary nested Python structures — close to how you'd handle JSON.
JavaScript / Node.js
Two solutions are popular in Node. fast-xml-parser parses XML into an object with no external dependencies and runs very fast.
const { XMLParser } = require("fast-xml-parser");
const fs = require("fs");
const xml = fs.readFileSync("catalog.xml", "utf-8");
const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: "@_" });
const data = parser.parse(xml);
for (const product of data.catalog.product) {
console.log(product.name, product.price["#text"], product["@_available"]);
}
An alternative is xml2js, long established in the ecosystem and handy for async processing. In the browser, the built-in DOMParser lets you traverse XML with the same methods you'd use on an HTML document.
PHP
For simple documents the built-in SimpleXML is ideal — it exposes elements as object properties.
<?php
$xml = simplexml_load_file("catalog.xml");
foreach ($xml->product as $product) {
$name = (string) $product->name;
$price = (string) $product->price;
$available = (string) $product["available"]; // attribute
echo "$name — $price — $available\n";
}
When you need namespaces, complex XPath, or streaming for large files, move to DOMDocument and XMLReader from the same standard PHP distribution.
Java
Java's standard library ships everything for both DOM and XPath through the javax.xml packages — no third-party dependency required. The DocumentBuilder builds the tree, and XPath queries it.
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.*;
import org.w3c.dom.*;
import java.io.File;
public class ParseCatalog {
public static void main(String[] args) throws Exception {
Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(new File("catalog.xml"));
XPath xpath = XPathFactory.newInstance().newXPath();
// XPath: every in-stock product
NodeList products = (NodeList) xpath.evaluate(
"//product[@available='true']", doc, XPathConstants.NODESET);
for (int i = 0; i < products.getLength(); i++) {
Element p = (Element) products.item(i);
String name = xpath.evaluate("name", p);
String price = xpath.evaluate("price", p);
System.out.println(name + " " + price);
}
}
}
For very large feeds, Java's streaming APIs — SAX and StAX (XMLStreamReader) — read the document event by event without holding it all in memory.
Go
Go's standard library has the encoding/xml package, which parses XML directly into structs via field tags.
package main
import (
"encoding/xml"
"fmt"
"os"
)
type Catalog struct {
Products []struct {
ID string `xml:"id,attr"`
Available string `xml:"available,attr"`
Name string `xml:"name"`
Price string `xml:"price"`
} `xml:"product"`
}
func main() {
data, _ := os.ReadFile("catalog.xml")
var c Catalog
xml.Unmarshal(data, &c)
for _, p := range c.Products {
fmt.Println(p.Name, p.Price, p.Available)
}
}
Common mistakes
Most problems come from encoding: if the declaration says ISO-8859-1 but the file is read as UTF-8, accented characters turn to garbage — either let the parser handle the encoding or re-decode explicitly. The second most frequent cause is ignored namespaces, which makes XPath queries silently return nothing. Third is trying to load an oversized file whole into DOM: a gigabyte feed must be read streaming. And finally, don't parse XML with regular expressions: the format is nested and recursive, and regexes break on the first non-standard case — that's fine for unstructured text (see parsing TXT) but not for XML.
FAQ
What's the difference between DOM and SAX parsing? DOM loads the entire document into a navigable in-memory tree — simple and flexible, but memory-hungry. SAX (and StAX) stream through the document firing events as they go, using almost no memory but requiring you to track state yourself. Use DOM by default; switch to streaming for very large files.
Is XPath worth learning for XML parsing?
Yes. XPath lets you express "every in-stock product under \$30" in a single query instead of nested loops, and it's supported by lxml, PHP's DOMXPath, Java's javax.xml.xpath, and more. It pays for itself the first time a feed's structure gets complicated.
Can I parse XML with regular expressions? No. XML is recursively nested, and regex can't reliably match balanced structure. Use a real parser — every language above ships one in its standard library.
Get your XML parsed for you
If your feeds have a non-standard export schema, broken namespaces, or run to gigabytes, our team can set up XML parsing tuned to your format as a data extraction service. And if the source data doesn't arrive as clean XML but as one of its derivatives, see the neighboring guides on RSS and sitemaps.