StAX XMLStreamWriter Namespaces and Prefixes
The Streaming API for XML (StAX) XMLStreamWriter
provides low-level, high-performance control over XML serialization,
including precise management of XML namespaces and prefix bindings. This
article explains how XMLStreamWriter handles namespace
declarations and prefix-to-URI mappings, detailing the distinction
between manual namespace control and the automatic namespace repairing
mode.
Manual Namespace Management
By default, standard XMLStreamWriter implementations do
not automatically declare namespaces or resolve prefixes unless
explicitly instructed. Writing namespaced XML requires two distinct
actions: binding the prefix within the writer’s internal state and
writing the actual namespace declaration to the output stream.
1. Binding Prefixes to URIs
Before writing elements or attributes that use a namespace, you must bind the prefix to the target Namespace URI in the current context using:
xmlStreamWriter.setPrefix(String prefix, String uri);For the default namespace, you use:
xmlStreamWriter.setDefaultNamespace(String uri);Calling setPrefix updates the internal
NamespaceContext of the writer for the current element
scope, allowing subsequent write methods to recognize the mapping.
However, setPrefix does not write anything to the
serialized XML output.
2. Writing Namespace Declarations
To emit the xmlns:prefix="URI" or
xmlns="URI" attributes into the XML output, you must
explicitly call:
xmlStreamWriter.writeNamespace(String prefix, String uri);or
xmlStreamWriter.writeDefaultNamespace(String uri);These methods must be called immediately after calling
writeStartElement() and before writing any child elements,
text content, or attributes.
Standard Manual Workflow
A typical manual namespace sequence follows this pattern:
// 1. Start the element
xmlStreamWriter.writeStartElement("ns", "item", "http://example.com/ns");
// 2. Bind the prefix for context resolution
xmlStreamWriter.setPrefix("ns", "http://example.com/ns");
// 3. Write the actual xmlns declaration to the output
xmlStreamWriter.writeNamespace("ns", "http://example.com/ns");
// 4. Write namespaced attributes if needed
xmlStreamWriter.writeAttribute("http://example.com/ns", "id", "123");
// 5. Close the element
xmlStreamWriter.writeEndElement();Namespace Context and Scoping
XMLStreamWriter maintains a stack of namespace contexts
that mirrors the element hierarchy:
- Scope Entry: When a new element is opened via
writeStartElement(), a new namespace scope is pushed onto the stack. - Inheritance: Child elements inherit all prefix bindings established in parent elements unless explicitly overridden.
- Scope Exit: When
writeEndElement()is called, the current scope is popped off the stack, discarding any bindings defined specifically within that element.
Because of this scoping behavior, you only need to call
writeNamespace() once at the root or ancestor level where
the namespace scope begins.
Automatic Namespace Repairing Mode
Manual management can be verbose and error-prone. StAX addresses this through “Namespace Repairing” mode, which delegates prefix assignment and namespace declaration to the writer.
To enable this mode, set the IS_REPAIRING_NAMESPACES
property on the XMLOutputFactory before creating the
writer:
XMLOutputFactory factory = XMLOutputFactory.newInstance();
factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE);
XMLStreamWriter writer = factory.createXMLStreamWriter(outputStream);How Repairing Mode Operates
When namespace repairing is active:
- Automatic Declaration: If you write an element or
attribute with a URI that has not been declared, the writer
automatically inserts the appropriate
xmlnsattribute. - Prefix Generation: If you specify a URI without a
prefix (e.g.,
writeStartElement("http://example.com/ns", "item")), the writer looks for an existing prefix for that URI. If none exists, it generates a unique prefix (such as@ns1,zdata0, etc.) and outputs the declaration. - Conflict Resolution: If a duplicate or conflicting prefix is detected in the current scope, the writer repairs the collision by generating a non-conflicting prefix for the new URI.
- No Explicit
writeNamespaceRequired: You can write elements and attributes directly using(URI, localName)pairs; the writer guarantees valid namespace output.