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 17+ with fluent builders, Stream-based navigation, and type-safe configuration
- 🌐 Namespace Aware: Comprehensive XML namespace support with resolution and context management
- ⚡ Performance: Minimal-change serialization - only modified sections are reformatted
Add DomTrip to your Maven project:
<dependency>
<groupId>eu.maveniverse.maven.domtrip</groupId>
<artifactId>domtrip-maven</artifactId>
<version>0.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();- 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
- 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
- 📊 Test Coverage: 100% (59/59 tests passing)
- 🔍 XML Conformance: Full XML 1.0 specification compliance
- ⚡ Performance: Optimized for both memory usage and processing speed
- 🛡️ Type Safety: Compile-time prevention of invalid XML operations
- 📝 Documentation: Comprehensive documentation with live examples
Create XML elements with convenient factory methods:
// Simple elements
Element version = Element.text("version", "1.0.0");
Element properties = Element.of("properties");
Element br = Element.selfClosing("br");
// Elements with attributes
Map<String, String> attrs = Map.of("scope", "test", "optional", "true");
Element dependency = Element.withAttributes("dependency", attrs);
// Namespaced elements
QName soapEnvelope = QName.of("http://schemas.xmlsoap.org/soap/envelope/", "Envelope", "soap");
Element nsElement = Element.of(soapEnvelope);
Element defaultNs = Element.of(QName.of("http://example.com/ns", "item"));
// Documents
Document doc = Document.of().root(Element.of("project"));
Document withDecl = Document.withXmlDeclaration("1.0", "UTF-8");Create complex XML structures with fluent APIs:
Element dependency = Element.of("dependency")
.attribute("scope", "test");
dependency.addNode(Element.text("groupId", "junit"));
dependency.addNode(Element.text("artifactId", "junit"));
dependency.addNode(Element.text("version", "4.13.2"));Navigate XML documents with Java Streams:
// Find all test dependencies
root.descendants()
.filter(e -> "dependency".equals(e.name()))
.filter(e -> "test".equals(e.attribute("scope")))
.forEach(dep -> System.out.println(dep.child("artifactId").map(Element::textContent).orElse("")));Work with XML namespaces naturally:
// Find elements by namespace URI and local name
QName soapBodyQName = QName.of("http://schemas.xmlsoap.org/soap/envelope/", "Body");
Optional<Element> soapBody = root.child(soapBodyQName);
// Create namespaced elements
Element element = Element.of("item")
.namespaceDeclaration("ex", "http://example.com/ns")
.namespaceDeclaration(null, "http://example.com/default");Customize DomTrip behavior for different use cases:
// Strict preservation (default)
DomTripConfig strict = DomTripConfig.defaults();
// Pretty printing for clean output
DomTripConfig pretty = DomTripConfig.prettyPrint()
.withIndentString(" ")
.withDefaultQuoteStyle(QuoteStyle.DOUBLE);
Editor editor = new Editor(Document.of(xml), pretty);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 presets
- 🔒 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 | ✅ Perfect | ❌ No | ❌ No | ❌ No |
| Comment Preservation | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No |
| Between-Element Whitespace | ✅ Exact | ✅ Yes* | ❌ No | |
| In-Element Whitespace | ✅ Exact | ❌ No | ❌ 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 17+ | ❌ Legacy | ❌ Legacy | ✅ Modern |
| Stream Navigation | ✅ Yes | ❌ No | ❌ No | ❌ No |
| Type Safety | ✅ Compile-time | ❌ Runtime | ❌ Runtime | ✅ Compile-time |
| Performance | ✅ Optimized | ✅ Fast | ✅ Fast | ✅ Very Fast |
* 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 testExplore DomTrip features with interactive demos:
# Core editing features
mvn test-compile exec:java -Dexec.mainClass="eu.maveniverse.domtrip.demos.EditorDemo" -Dexec.classpathScope=test
# Builder patterns
mvn test-compile exec:java -Dexec.mainClass="eu.maveniverse.domtrip.demos.BuilderPatternsDemo" -Dexec.classpathScope=test
# Navigation features
mvn test-compile exec:java -Dexec.mainClass="eu.maveniverse.domtrip.demos.NavigationDemo" -Dexec.classpathScope=test
# Configuration options
mvn test-compile exec:java -Dexec.mainClass="eu.maveniverse.domtrip.demos.ConfigurationDemo" -Dexec.classpathScope=test
# Namespace handling
mvn test-compile exec:java -Dexec.mainClass="eu.maveniverse.domtrip.demos.NamespaceDemo" -Dexec.classpathScope=testcd website
npm install
npm start # Development server
npm run build # Production buildOriginal XML:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Sample Maven POM -->
<project xmlns="http://maven.apache.org/POM/4.0.0">
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0</version>
</project>After editing with DomTrip:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Sample Maven POM -->
<project xmlns="http://maven.apache.org/POM/4.0.0">
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>2.0.0</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>Notice how:
- ✅ Original formatting preserved (XML declaration, comments, indentation)
- ✅ Only modified elements (
version) and new elements (dependencies) changed - ✅ New elements follow inferred indentation patterns
- ✅ Comments and namespace declarations maintained
We welcome contributions! Please see our Contributing Guide for details.
DomTrip is licensed under the Eclipse Public License 2.0.
- 📖 Documentation
- 📦 Maven Central
- 🐛 Issues
- 💬 Discussions
DomTrip - Perfect XML round-trips, every time 🔄