Lossless XML Editing for Java
DomTrip is a Java library for lossless XML editing that preserves every detail of your XML documents during round-trip operations. Perfect for configuration file editing, document transformation, and any scenario where maintaining original formatting is crucial.
- Perfect Round-Trip: Preserves comments, whitespace, entity encoding, attribute quote styles, and formatting
- Easy Editing: Make changes while keeping original formatting intact
- Modern API: Built for Java 8+ with fluent builders, Stream-based navigation, and type-safe configuration
- Namespace Aware: Comprehensive XML namespace support with resolution and context management
- XPath Queries: Built-in mini-XPath for common queries, plus full XPath 1.0 via the Jaxen module
- Structural Diff: XML-aware diff that distinguishes semantic changes from formatting-only changes
- SAX Interop: Emit SAX events from DomTrip documents for JAXP pipeline integration
- JPMS Ready: Ships with
module-info.javadescriptors - Well Tested: 1900+ tests covering XML conformance, round-trip fidelity, and edge cases
Add DomTrip to your Maven project:
<dependency>
<groupId>eu.maveniverse.maven.domtrip</groupId>
<artifactId>domtrip-core</artifactId>
<version>1.2.0</version>
</dependency>For Maven POM editing (includes core):
<dependency>
<groupId>eu.maveniverse.maven.domtrip</groupId>
<artifactId>domtrip-maven</artifactId>
<version>1.2.0</version>
</dependency>For full XPath 1.0 support (includes core):
<dependency>
<groupId>eu.maveniverse.maven.domtrip</groupId>
<artifactId>domtrip-jaxen</artifactId>
<version>1.2.0</version>
</dependency>// Load and edit XML while preserving formatting
Editor editor = new Editor(Document.of(xmlString));
// Make targeted changes
Element version = editor.root().descendant("version").orElseThrow();
editor.setTextContent(version, "2.0.0");
// Add new elements with automatic formatting
Element dependencies = editor.root().descendant("dependencies").orElseThrow();
Element newDep = editor.addElement(dependencies, "dependency");
editor.addElement(newDep, "groupId", "junit");
editor.addElement(newDep, "artifactId", "junit");
// Get result with preserved formatting
String result = editor.toXml();| Module | Artifact | Description |
|---|---|---|
| core | domtrip-core |
Parser, serializer, editor, diff, visitor, XPath mini-language, SAX output |
| maven | domtrip-maven |
Maven POM-specific editing utilities |
| jaxen | domtrip-jaxen |
Full XPath 1.0 support via the Jaxen engine |
- Comments: Multi-line comments, inline comments, document comments
- Whitespace: Exact spacing, indentation, and line breaks
- Entities: Custom entity encoding (
<,&,") - Attributes: Quote styles (single vs double quotes), ordering, spacing
- Declarations: XML declarations, processing instructions, DTDs
- Fluent Builders:
Element.builder("dependency").withAttribute("scope", "test").build() - Stream Navigation:
root.descendants().filter(e -> "dependency".equals(e.getName())) - Optional Safety:
element.findChild("version").ifPresent(v -> ...) - Type Safety: Compile-time prevention of invalid operations
- Configuration: Preset configurations for different use cases
Built-in mini-XPath handles the most common query patterns without any extra dependencies:
// Path navigation with predicates
root.xpath("dependencies/dependency[@scope='test']");
root.xpath("//version");
root.xpath("dependency[groupId='junit']/version");For full XPath 1.0 support, add the domtrip-jaxen module:
DomTripXPath xpath = new DomTripXPath("//dependency[starts-with(groupId, 'org.')]");
List<?> results = xpath.selectNodes(root);Structured depth-first tree traversal with enter/exit callbacks:
// Visitor interface
element.accept(new DomTripVisitor() {
@Override
public Action enterElement(Element e) {
System.out.println("Entering: " + e.name());
return Action.CONTINUE;
}
});
// Lambda-friendly TreeWalker
element.walk()
.onEnter(e -> {
System.out.println(e.name());
return DomTripVisitor.Action.CONTINUE;
})
.execute();Compare documents with XML-aware diff that distinguishes semantic changes from formatting-only changes:
Document before = Document.of(oldXml);
Document after = Document.of(newXml);
DiffResult diff = XmlDiff.diff(before, after);
for (XmlChange change : diff.changes()) {
System.out.println(change);
}
// ELEMENT_ADDED: /project/dependencies/dependency[3]
// TEXT_CHANGED: /project/version: "1.0" -> "1.1"Bridge DomTrip documents into SAX-based pipelines and JAXP APIs:
// Emit SAX events
SAXOutputter outputter = new SAXOutputter();
outputter.output(doc, contentHandler);
// Use as a JAXP SAXSource (e.g. with Transformer or Validator)
SAXSource source = DomTripSAXSource.of(doc);
transformer.transform(source, result);- Namespace-Aware Navigation: Find elements by namespace URI and local name
- Context Management: Automatic namespace resolution and prefix handling
- Builder Integration: Create namespaced elements with fluent builders
- Preservation: Maintains namespace declarations and prefixes
- Getting Started - Installation and quick start guide
- Core Features - Lossless parsing, formatting preservation, namespaces
- API Reference - Complete API documentation
- Examples - Real-world usage examples
- Library Comparison - How DomTrip compares to other XML libraries
DomTrip uses a clean, type-safe architecture that enforces XML structure rules:
Node (abstract base)
├── ContainerNode (abstract)
│ ├── Document (root container)
│ └── Element (XML elements)
└── Leaf Nodes
├── Text (text content, CDATA)
├── Comment (XML comments)
└── ProcessingInstruction (PIs)
Editor- High-level editing interface with formatting preservationParser- XML parsing engine that captures all formatting metadataSerializer- Minimal-change XML output generationDomTripConfig- Configuration management with presetsXPathExpression- Mini-XPath query engine for element lookupXmlDiff- XML-aware structural diff engineDomTripVisitor/TreeWalker- Depth-first tree traversalSAXOutputter- SAX event emission for JAXP interop
- Preservation First - Original formatting preserved unless explicitly modified
- Metadata Tracking - Each node tracks modification state and formatting
- Minimal Changes - Only modified sections are reformatted
- Type Safety - Compile-time prevention of invalid operations
DomTrip excels in scenarios where preserving original formatting is crucial:
- Configuration Files - Update Maven POMs, Spring configs, web.xml while preserving comments and formatting
- Document Transformation - Transform XML documents while maintaining original structure and style
- XML Editing Tools - Build XML editors and IDEs that respect user formatting preferences
- Template Processing - Process XML templates while preserving formatting for human readability
- Build Tools - Modify build files programmatically without disrupting team formatting standards
| Feature | DomTrip | DOM4J | JDOM | Jackson XML |
|---|---|---|---|---|
| Lossless Round-Trip | Yes | No | No | No |
| Comment Preservation | Yes | Yes | Yes | No |
| Between-Element Whitespace | Exact | Partial | Yes* | No |
| In-Element Whitespace | Exact | No | Configurable | No |
| Quote Style Preservation | Yes | No | No | No |
| Attribute Order Preservation | Yes | No | No | No |
| Entity Preservation | Yes | No | No | No |
| Modern Java API | Java 8+ | Legacy | Legacy | Modern |
| Stream Navigation | Yes | No | No | No |
| XPath | Built-in + Jaxen | Jaxen | Built-in | No |
| Structural Diff | Built-in | No | No | No |
| SAX Output | Yes | Yes | Yes | No |
| Type Safety | Compile-time | Runtime | Runtime | Compile-time |
* JDOM Notes:
Format.getRawFormat()preserves original whitespace between elementsFormat.getPrettyFormat()reformats with consistent indentation- Text content whitespace configurable via
TextMode.PRESERVE/TRIM/NORMALIZE
Choose DomTrip when: You need perfect formatting preservation for config files, documentation, or human-edited XML
Choose others when: You only need data extraction, transformation, or high-throughput processing
mvn testcd website
npm install
npm start # Development server
npm run build # Production buildWe welcome contributions! Please see our Contributing Guide for details.
DomTrip is licensed under the Eclipse Public License 2.0.
DomTrip - Perfect XML round-trips, every time