Namespaces

How URIs disambiguate element names, how default and prefixed namespaces differ, and the attribute trap that breaks XPath queries.

Why namespaces exist

Two vocabularies can both define an element called <title>. A namespace makes the name globally unambiguous by binding a prefix to a URI. The URI is an identifier, not an address — nothing is ever fetched from it.

TermExampleMeaning
PrefixsvgA local alias, arbitrary and rebindable
Namespace URIhttp://www.w3.org/2000/svgThe globally unique identity
Local namerectThe part after the colon
Qualified namesvg:rectPrefix plus local name
Default namespacexmlns="..."Applies to unprefixed elements only

Declaring and using them

<!-- prefix declarations are scoped to the element and its descendants -->
<root xmlns:dc="http://purl.org/dc/elements/1.1/"
      xmlns:x="http://www.w3.org/1999/xhtml">
  <dc:title>Namespaces</dc:title>
  <x:p>Body text</x:p>
</root>

<!-- a default namespace: every unprefixed element belongs to it -->
<feed xmlns="http://www.w3.org/2005/Atom">
  <entry>
    <id>urn:uuid:1</id>   <!-- same namespace as feed -->
  </entry>
</feed>

<!-- undeclaring it puts an element back in no namespace -->
<feed xmlns="http://www.w3.org/2005/Atom">
  <entry xmlns="">
    <id>no-namespace-here</id>
  </entry>
</feed>
  • Prefixes are local aliases: the same URI may appear as dc in one document and dcterms in another.
  • Because the URI defines identity, renaming a prefix never changes a document's meaning.
  • xml:lang and xml:space live in the reserved namespace http://www.w3.org/XML/1998/namespace and need no declaration.
  • Two elements with the same local name in different namespaces are unrelated to any parser.
⚠️
A default namespace does not apply to attributes. In <feed xmlns="http://www.w3.org/2005/Atom" type="x"> the element is in the Atom namespace while type is in no namespace — which is exactly where an XPath predicate looking for @type will fail.

Working with namespaced documents

Namespaces are the most common reason an XPath query silently returns nothing. In XPath 1.0 an unprefixed name selects from the no-namespace set and never from the document's default namespace.

from lxml import etree

doc = etree.fromstring(b'<feed xmlns="http://www.w3.org/2005/Atom"><id>u1</id></feed>')

print(doc.xpath("/feed"))                                   # [] - no namespace match
ns = {"a": "http://www.w3.org/2005/Atom"}
print(doc.xpath("/a:feed/a:id/text()", namespaces=ns))      # ['u1']

# a local-name() test avoids registering a prefix, but cannot use indexes
print(doc.xpath("/*[local-name()='feed']/*[local-name()='id']/text()"))
  • Register a prefix for every namespace present before writing queries.
  • URIs must match character for character — a trailing slash selects nothing.
  • In XPath 2.0 and later you can set a default element namespace, which is why modern XSLT avoids some of this.
  • When merging documents, rewrite URIs only when the meaning changed; never rewrite prefixes to make them look tidy.

FAQ

Is the namespace URI ever fetched?
No. It exists purely for identity, which is why it can be a URL that returns 404 or an opaque URN. Parsers never resolve it.
Can two prefixes bind to the same URI?
Yes, and both are legal. They select the same elements, so pick one convention per document for readability.

XML syntax and well-formedness Location paths and axes

Last refreshed 2026-09-18.