Data & Formats 6 min read

XML Parsing: Libraries, XPath, and Examples in Any Language

XML parsing explained: DOM, SAX, and XPath approaches with library picks and code examples in Python, PHP, Java, and Go. Read the guide to parse any feed.

ST
Scraping.Pro Team
Data collection for business needs
Published: 23 May 2025

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.

xml
<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.

python
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.

python
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.

javascript
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
<?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.

java
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.

go
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.