Namespace Support

DomTrip provides comprehensive support for XML namespaces, allowing you to work with complex XML documents that use multiple namespaces while preserving all namespace declarations and prefixes.

Understanding XML Namespaces

XML namespaces allow you to avoid naming conflicts when combining XML vocabularies:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <groupId>com.example</groupId>
    <artifactId>my-app</artifactId>
</project>

Namespace-Aware Navigation

DomTrip provides several methods for namespace-aware navigation:

Finding Elements by Namespace

String xmlWithNamespaces = createMavenPomXml();
Document doc = Document.of(xmlWithNamespaces);
Editor editor = new Editor(doc);

// Find by namespace URI and local name
Element project = editor.root();
Element groupId = project.descendant("groupId").orElseThrow();

// Find all elements in a namespace
long pomElementCount = project.descendants()
        .filter(e -> "http://maven.apache.org/POM/4.0.0".equals(e.namespaceURI()))
        .count();

// Find with qualified name
Element modelVersion = project.child("modelVersion").orElseThrow();

Working with Default Namespaces

String xml =
        """
    <project xmlns="http://maven.apache.org/POM/4.0.0">
        <groupId>com.example</groupId>
        <artifactId>my-app</artifactId>
    </project>
    """;

Document doc = Document.of(xml);
Editor editor = new Editor(doc);

Element root = doc.root();

// Access namespace information
String namespace = root.namespaceURI(); // "http://maven.apache.org/POM/4.0.0"
String localName = root.localName(); // "project"
String qualifiedName = root.qualifiedName(); // "project"

Namespace Declaration Management

DomTrip preserves all namespace declarations and allows you to manage them:

Reading Namespace Information

String xml =
        """
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <groupId>com.example</groupId>
        <xsi:schemaLocation>http://maven.apache.org/POM/4.0.0
                            http://maven.apache.org/xsd/maven-4.0.0.xsd</xsi:schemaLocation>
    </project>
    """;

Document doc = Document.of(xml);
Editor editor = new Editor(doc);

Element schemaLocation = doc.root().child("xsi:schemaLocation").orElseThrow();

// Access prefixed element information
String namespace = schemaLocation.namespaceURI(); // "http://www.w3.org/2001/XMLSchema-instance"
String localName = schemaLocation.localName(); // "schemaLocation"
String prefix = schemaLocation.prefix(); // "xsi"
String qualifiedName = schemaLocation.qualifiedName(); // "xsi:schemaLocation"

Managing Namespace Declarations

String xml = createMavenPomXml();
Document doc = Document.of(xml);
Editor editor = new Editor(doc);
Element root = editor.root();

// Add namespace declaration
root.namespaceDeclaration("custom", "http://example.com/custom");

// Remove namespace declaration (if it exists)
// root.removeNamespaceDeclaration("unused");

// Get all namespace declarations
String defaultNs = root.namespaceDeclaration("");
String customNs = root.namespaceDeclaration("custom");

Creating Namespaced Elements

When creating new elements, you can specify their namespace:

Using Namespace URIs

String xml = createTestXml("parent");
Document doc = Document.of(xml);
Editor editor = new Editor(doc);
Element parent = editor.root();

// Create element in specific namespace
Element customElement = Element.of("item")
        .namespaceDeclaration(null, "http://example.com/custom")
        .attribute("id", "123");

// Add to document
parent.addNode(customElement);

String result = editor.toXml();

Namespace Context

DomTrip maintains namespace context throughout the document tree:

Element element = editor.findElement("someElement");

// Get namespace context at this element
NamespaceContext context = element.getNamespaceContext();

// Resolve prefix to URI
String uri = context.getNamespaceURI("custom");

// Get prefix for URI
String prefix = context.getPrefix("http://example.com/custom");

// Get all prefixes for a URI
Iterator<String> prefixes = context.getPrefixes("http://example.com/custom");

Working with Schema Locations

DomTrip handles schema location attributes specially:

Element root = editor.getDocumentElement();

// Get schema locations
String schemaLocation = root.getAttribute("xsi:schemaLocation");

// Update schema location
root.setAttribute("xsi:schemaLocation", 
    "http://maven.apache.org/POM/4.0.0 " +
    "http://maven.apache.org/xsd/maven-4.0.0.xsd");

Namespace Validation

DomTrip can validate namespace usage:

DomTripConfig config = DomTripConfig.defaults()
    .withValidateNamespaces(true)
    .withRequireNamespaceDeclarations(true);

try {
    Editor editor = new Editor(xml, config);
    // Will throw exception if namespaces are invalid
} catch (InvalidNamespaceException e) {
    System.err.println("Namespace error: " + e.getMessage());
}

Common Patterns

SOAP Documents

// Working with SOAP envelopes
String soapNamespace = "http://schemas.xmlsoap.org/soap/envelope/";

String soapXml =
        """
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <soap:Body>
            <GetUserRequest>
                <userId>123</userId>
            </GetUserRequest>
        </soap:Body>
    </soap:Envelope>
    """;

Document doc = Document.of(soapXml);
Editor editor = new Editor(doc);

Element soapBody = editor.root().child("soap:Body").orElseThrow();

if (soapBody != null) {
    // Process SOAP body content
    Element request = soapBody.child("GetUserRequest").orElseThrow();
    Element userId = request.child("userId").orElseThrow();

    Assertions.assertEquals("123", userId.textContent());
}

Maven POMs

// Working with Maven POM files
String pomNamespace = "http://maven.apache.org/POM/4.0.0";
String xml = createMavenPomXml();

Document doc = Document.of(xml);
Editor editor = new Editor(doc);

Element dependencies = editor.root().child("dependencies").orElse(null);
if (dependencies == null) {
    // Create dependencies section
    dependencies = editor.addElement(editor.root(), "dependencies");
}

// Add a new dependency
Element newDep = editor.addElement(dependencies, "dependency");
editor.addElement(newDep, "groupId", "junit");
editor.addElement(newDep, "artifactId", "junit");
editor.addElement(newDep, "version", "4.13.2");

Configuration Files

// Working with Spring configuration
String springNamespace = "http://www.springframework.org/schema/beans";
String contextNamespace = "http://www.springframework.org/schema/context";

// Find Spring beans
Stream<Element> beans = editor.getDocumentElement()
    .descendantsByNamespace(springNamespace, "bean");

// Find context annotations
Optional<Element> componentScan = editor.getDocumentElement()
    .findChildByNamespace(contextNamespace, "component-scan");

Best Practices

1. Use Namespace URIs for Reliability

String xml = createMavenPomXml();
Document doc = Document.of(xml);
Editor editor = new Editor(doc);

// ✅ Good - uses namespace URI (conceptually)
Element root = editor.root();
String namespace = root.namespaceURI();

// ✅ Good - reuse existing declarations
if (root.namespaceDeclaration("custom") == null) {
    root.namespaceDeclaration("custom", "http://example.com/custom");
}

// ✅ Good - explicit namespace when creating elements
Element element = Element.of("custom:item").namespaceDeclaration("custom", "http://example.com/custom");

Configuration Options

Control namespace handling through configuration:

DomTripConfig config = DomTripConfig.defaults()
    .withPreserveNamespaceDeclarations(true)  // Keep all declarations
    .withValidateNamespaces(true)             // Validate namespace usage
    .withRequireNamespaceDeclarations(false)  // Allow undeclared prefixes
    .withDefaultNamespacePrefix("ns");        // Prefix for default namespace

Next Steps