XML Tutorial · XML Basics · Lesson 6 of 28
XML Namespaces
Why namespaces exist, prefixes and default namespaces, and how to query namespaced XML without getting empty results.
The problem namespaces solve
Two vocabularies can use the same tag name for different things: an HTML <table> and a furniture <table>. A
namespace gives each name a globally unique identity: a URI plus the local name.
<catalog xmlns="urn:example:shop"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<product sku="TEA-01">
<dc:title>Green tea</dc:title>
<price>3.50</price>
</product>
</catalog>
xmlns="urn:example:shop"sets the default namespace for this element and its descendants without a prefix.xmlns:dc="…"binds the prefixdcto a namespace URI;dc:titleis in that namespace.- The URI is just an identifier; nothing is downloaded from it.
- Attributes without a prefix are in no namespace, even inside a default namespace.
- The prefix is only a shorthand. What matters is the URI:
<a:x xmlns:a="urn:u"/>and<b:x xmlns:b="urn:u"/>are the same element.
APIs write a namespaced name in "Clark notation", {urn:example:shop}price.
The classic bug: empty results
Code that ignores the default namespace finds nothing:
from lxml import etree
doc = etree.fromstring(b'<catalog xmlns="urn:example:shop"><product><price>3.50</price></product></catalog>')
print("tag is really:", doc.tag)
print("without namespace:", doc.findall("product"), doc.xpath("//price"))
print("with namespace: ", [p.text for p in doc.iter("{urn:example:shop}price")])
Output
tag is really: {urn:example:shop}catalog
without namespace: [] []
with namespace: ['3.50']Querying with namespaces
Map prefixes of your choice to the URIs and use them in your queries. The prefixes in the query don't need to match the document's:
from lxml import etree
doc = etree.fromstring(b"""<catalog xmlns="urn:example:shop" xmlns:dc="http://purl.org/dc/elements/1.1/">
<product sku="TEA-01"><dc:title>Green tea</dc:title><price>3.50</price></product>
<product sku="MUG-07"><dc:title>Camel mug</dc:title><price>12.00</price></product>
</catalog>""")
ns = {"s": "urn:example:shop", "dc": "http://purl.org/dc/elements/1.1/"}
for p in doc.xpath("//s:product", namespaces=ns):
print(p.get("sku"), p.xpath("string(dc:title)", namespaces=ns), p.xpath("string(s:price)", namespaces=ns))
Output
TEA-01 Green tea 3.50 MUG-07 Camel mug 12.00
<?php
$doc = new DOMDocument();
$doc->loadXML('<catalog xmlns="urn:example:shop" xmlns:dc="http://purl.org/dc/elements/1.1/">
<product sku="TEA-01"><dc:title>Green tea</dc:title><price>3.50</price></product>
<product sku="MUG-07"><dc:title>Camel mug</dc:title><price>12.00</price></product>
</catalog>');
$xp = new DOMXPath($doc);
$xp->registerNamespace("s", "urn:example:shop");
$xp->registerNamespace("dc", "http://purl.org/dc/elements/1.1/");
foreach ($xp->query("//s:product") as $p) {
echo $p->getAttribute("sku"), " ", $xp->evaluate("string(dc:title)", $p), " ",
$xp->evaluate("string(s:price)", $p), "\n";
}
Output
TEA-01 Green tea 3.50 MUG-07 Camel mug 12.00
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.*;
import org.w3c.dom.*;
import java.io.ByteArrayInputStream;
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
String xml = """
<catalog xmlns="urn:example:shop" xmlns:dc="http://purl.org/dc/elements/1.1/">
<product sku="TEA-01"><dc:title>Green tea</dc:title><price>3.50</price></product>
<product sku="MUG-07"><dc:title>Camel mug</dc:title><price>12.00</price></product>
</catalog>""";
var factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // off by default in Java!
Document doc = factory.newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes("UTF-8")));
Map<String, String> ns = Map.of("s", "urn:example:shop", "dc", "http://purl.org/dc/elements/1.1/");
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) { return ns.getOrDefault(prefix, XMLConstants.NULL_NS_URI); }
public String getPrefix(String uri) { return null; }
public Iterator<String> getPrefixes(String uri) { return null; }
});
NodeList products = (NodeList) xp.evaluate("//s:product", doc, XPathConstants.NODESET);
for (int i = 0; i < products.getLength(); i++) {
Element p = (Element) products.item(i);
System.out.println(p.getAttribute("sku") + " " + xp.evaluate("string(dc:title)", p) + " "
+ xp.evaluate("string(s:price)", p));
}
}
}
Output
TEA-01 Green tea 3.50 MUG-07 Camel mug 12.00
Run this on your computer — see “Get Started” for setup.
XPath 1.0 has no syntax for "the default namespace", so you always need a prefix for namespaced elements, even
if the document itself uses none. In Java, remember setNamespaceAware(true); it's off by default.
Test yourself
In <shop xmlns='urn:s'><item code='1'/></shop>, which namespace is the attribute code in?
urn:sNo namespaceThe xml namespaceIt inherits the parent's prefix
Show answer
Answer: No namespace
Default namespaces apply to unprefixed element names only; unprefixed attributes are in no namespace.