Skip to content

maveniverse/domtrip

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

DomTrip

Lossless XML Editing for Java

Maven Central GitHub Documentation

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.

🎯 Why DomTrip?

  • πŸ”„ 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

πŸš€ Quick Start

Installation

Add DomTrip to your Maven project:

<dependency>
    <groupId>eu.maveniverse.maven.domtrip</groupId>
    <artifactId>domtrip-maven</artifactId>
    <version>0.2.0</version>
</dependency>

Basic Usage

// 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();

✨ Key Features

Lossless Preservation

  • Comments: Multi-line comments, inline comments, document comments
  • Whitespace: Exact spacing, indentation, and line breaks
  • Entities: Custom entity encoding (&lt;, &amp;, &quot;)
  • Attributes: Quote styles (single vs double quotes), ordering, spacing
  • Declarations: XML declarations, processing instructions, DTDs

Modern Java API

  • 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 Support

  • 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

πŸ“š Documentation

πŸ“– Complete Documentation

πŸ§ͺ Quality Assurance

  • πŸ“Š 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

πŸ—οΈ Advanced Features

Factory Methods

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");

Fluent API

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"));

Stream-Based Navigation

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("")));

Namespace-Aware Operations

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");

Configuration Management

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);

πŸ›οΈ Architecture

DomTrip uses a clean, type-safe architecture that enforces XML structure rules:

Node Hierarchy

Node (abstract base)
β”œβ”€β”€ ContainerNode (abstract)
β”‚   β”œβ”€β”€ Document (root container)
β”‚   └── Element (XML elements)
└── Leaf Nodes
    β”œβ”€β”€ Text (text content, CDATA)
    β”œβ”€β”€ Comment (XML comments)
    └── ProcessingInstruction (PIs)

Core Components

  • Editor - High-level editing interface with formatting preservation
  • Parser - XML parsing engine that captures all formatting metadata
  • Serializer - Minimal-change XML output generation
  • DomTripConfig - Configuration management with presets

Design Principles

  1. πŸ”’ Preservation First - Original formatting preserved unless explicitly modified
  2. πŸ“Š Metadata Tracking - Each node tracks modification state and formatting
  3. ⚑ Minimal Changes - Only modified sections are reformatted
  4. πŸ›‘οΈ Type Safety - Compile-time prevention of invalid operations

πŸ’‘ Use Cases

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

🎯 Comparison with Other Libraries

Feature DomTrip DOM4J JDOM Jackson XML
Lossless Round-Trip βœ… Perfect ❌ 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 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 elements
  • Format.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

πŸ§ͺ Development

Running Tests

mvn test

Interactive Demos

Explore 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=test

Building Documentation

cd website
npm install
npm start  # Development server
npm run build  # Production build

πŸ“‹ Example: Before and After

Original 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

🀝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

πŸ“„ License

DomTrip is licensed under the Eclipse Public License 2.0.

πŸ”— Links


DomTrip - Perfect XML round-trips, every time πŸ”„

About

The lossless XML editing library for Java

Resources

License

Stars

Watchers

Forks

Contributors 3

  •  
  •  
  •