XML in Python, Java and JavaScript
ElementTree and lxml, JAXP and JAXB, DOMParser and XMLSerializer in the browser, and the namespace-aware versus namespace-ignorant API split that causes most confusion.
Python: ElementTree and lxml
import xml.etree.ElementTree as ET
NS = {"s": "urn:example:shop"}
root = ET.fromstring('<order xmlns="urn:example:shop" id="1"><total>19.99</total></order>')
# a namespaced tag is stored as {uri}local, so the bare name finds nothing
print(root.findtext("total")) # None
print(root.findtext("s:total", NS)) # '19.99'
# writing a document: declare the namespace once, use the prefix
ET.register_namespace("s", "urn:example:shop")
print(ET.tostring(root, encoding="unicode"))# lxml adds XPath, XSLT and schema validation
from lxml import etree
doc = etree.parse("orders.xml")
nsmap = {"s": "urn:example:shop"}
for total in doc.xpath("//s:order/s:total/text()", namespaces=nsmap):
print(total)
schema = etree.XMLSchema(etree.parse("order.xsd"))
print(schema.validate(doc), schema.error_log.filter_from_errors())- The standard library is namespace-aware but offers no XPath; lxml provides both and is the common production choice.
- A parser with
resolve_entities=Truewill expand external entities, so keep that setting off for untrusted input. ET.register_namespaceaffects serialisation only; it does not change the parsed model.- Attribute lookup with a namespace requires the qualified name:
elem.get("{uri}attr").
Java: JAXP and JAXB
// DOM with hardened defaults
DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
f.setNamespaceAware(true);
f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
f.setFeature("http://xml.org/sax/features/external-general-entities", false);
f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
Document doc = f.newDocumentBuilder().parse(new File("orders.xml"));
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new SimpleNamespaceContext(Map.of("s", "urn:example:shop")));
String total = (String) xp.evaluate("string(//s:order/s:total)", doc, XPathConstants.STRING);
// JAXB maps XML to annotated classes; bundled through Jakarta XML Bind now
@XmlRootElement(name = "order", namespace = "urn:example:shop")
public class Order {
@XmlAttribute public String id;
@XmlElement(name = "total") public BigDecimal total;
}| Need | API | Note |
|---|---|---|
| Tree with queries | DOM plus XPath | Namespace aware must be enabled explicitly |
| Streaming | SAX or StAX | StAX is a pull model and easier to read |
| Object mapping | JAXB | Fast to write, brittle on schema change unless configured |
| Schema validation | SchemaFactory | Set the schema language explicitly |
| Hardened parsing | Factory features | Every factory needs its own configuration |
JavaScript in the browser
const text = '<order xmlns="urn:example:shop" id="1"><total>19.99</total></order>';
const doc = new DOMParser().parseFromString(text, "application/xml");
if (doc.querySelector("parsererror")) {
throw new Error("invalid XML");
}
// namespace-aware query
const NS = "urn:example:shop";
const total = doc.getElementsByTagNameNS(NS, "total")[0].textContent;
// serialise back out; note the closing tag hazard below
const out = new XMLSerializer().serializeToString(doc);
// building a document safely, with no string concatenation
const parser = new DOMParser();
const builder = parser.parseFromString("<root/>", "application/xml");
const el = builder.createElementNS(NS, "s:total");
el.textContent = "19.99";
builder.documentElement.appendChild(el);getElementsByTagNameignores namespaces;getElementsByTagNameNSdoes not. Mixing them is the usual cause of an empty result.- Inline XML in a page is an XML island and is subject to the page's parsing rules, so it must be well-formed at all times.
- Setting
textContentescapes automatically, which is why the DOM API is safer than string building. - Injecting serialised XML into a page as markup reintroduces the script-injection problem, so never treat it as trusted HTML.
💡
A namespace-aware API returns a qualified name; a namespace-ignorant one returns only the local name. Choose one model and be consistent, because code that mixes them works by accident until a document with two namespaces appears.
FAQ
Why does findtext return nothing even though the tag exists?
The document uses a default namespace, so the real tag is
{uri}total. Pass a namespace map or use the qualified name.Which Java XML API should new code use?
StAX for streaming and DOM with XPath for small documents. JAXB is convenient but adds a mapping layer that must be maintained as the schema evolves.
Related
Parsing XML in code: DOM, SAX and pull parsers RSS, Atom and web feeds
Last refreshed 2026-09-18.