Quick Start
Get up and running with DomTrip in 5 minutes! This guide covers the essential operations you'll use most often.
Your First DomTrip Program
Let's start with a simple example that demonstrates DomTrip's core strength: lossless round-trip editing.
// Parse XML while preserving all formatting
String originalXml =
"""
<?xml version="1.0" encoding="UTF-8"?>
<!-- Configuration file -->
<config>
<database>
<host>localhost</host>
<port>5432</port>
</database>
</config>
""";
Document doc = Document.of(originalXml);
Editor editor = new Editor(doc);
// Make some changes
Element database = editor.root().descendant("database").orElseThrow();
editor.addElement(database, "username", "admin");
editor.addElement(database, "password", "secret");
// Serialize back to XML
String result = editor.toXml();
System.out.println(result);
Output:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Configuration file -->
<config>
<database>
<host>localhost</host>
<port>5432</port>
<username>admin</username>
<password>secret</password>
</database>
</config>
Notice how:
- The XML declaration and comments are preserved
- Original indentation is maintained
- New elements follow the existing formatting pattern
Core Operations
1. Loading XML
// From string
String xmlString = createConfigXml();
Document doc = Document.of(xmlString);
Editor editor = new Editor(doc);
// From file (recommended - handles encoding automatically)
// import java.nio.file.Path;
Document doc2 = Document.of(tempFile);
Editor editor2 = new Editor(doc2);
// From InputStream with automatic encoding detection
// import java.io.InputStream;
// import java.nio.file.Files;
// import java.nio.file.Path;
try (InputStream inputStream = Files.newInputStream(tempFile)) {
Document doc3 = Document.of(inputStream);
Editor editor3 = new Editor(doc3);
Assertions.assertEquals("config", editor3.root().name());
}
// With custom configuration
Document docWithConfig = Document.of(xmlString);
Editor editorWithConfig = new Editor(docWithConfig, DomTripConfig.prettyPrint());
2. Finding Elements
String xml = createConfigXml();
Document doc = Document.of(xml);
Editor editor = new Editor(doc);
// Find by name
Element root = editor.root();
Element database = root.descendant("database").orElseThrow();
// Modern navigation with Optional
Optional<Element> host = database.child("host");
if (host.isPresent()) {
System.out.println("Host: " + host.orElseThrow().textContent());
}
String xml = createConfigXml();
Document doc = Document.of(xml);
Editor editor = new Editor(doc);
// Stream-based navigation
editor.root()
.descendants()
.filter(e -> e.name().equals("port"))
.findFirst()
.ifPresent(port -> System.out.println("Port: " + port.textContent()));
3. Adding Elements
String xml = createTestXml("parent");
Document doc = Document.of(xml);
Editor editor = new Editor(doc);
Element parent = editor.root();
// Simple element with text
editor.addElement(parent, "name", "value");
// Element with attributes
Element element = editor.addElement(parent, "dependency");
editor.setAttribute(element, "scope", "test");
editor.addElement(element, "groupId", "junit");
String xml = createTestXml("parent");
Document doc = Document.of(xml);
Editor editor = new Editor(doc);
Element parent = editor.root();
// Using element builders for complex structures
Element dependency = editor.addElement(parent, "dependency");
editor.addElement(dependency, "groupId", "org.example");
editor.addElement(dependency, "artifactId", "my-library");
editor.addElement(dependency, "version", "1.0.0");
editor.setAttribute(dependency, "scope", "compile");
4. Modifying Content
String xml = createConfigXml();
Document doc = Document.of(xml);
Editor editor = new Editor(doc);
// Change text content
Element version = editor.root().descendant("version").orElseThrow();
editor.setTextContent(version, "2.0.0");
// Modify attributes
Element database = editor.root().descendant("database").orElseThrow();
editor.setAttribute(database, "id", "main-db");
// Add comments
editor.addComment(editor.root(), " This is a comment ");
5. Removing Elements
String xml = createConfigXml();
Document doc = Document.of(xml);
Editor editor = new Editor(doc);
// Remove element by reference
Element database = editor.root().descendant("database").orElseThrow();
editor.removeElement(database);
// Remove by finding first occurrence
Element version = editor.root().descendant("version").orElse(null);
if (version != null) {
editor.removeElement(version);
}
Working with Namespaces
DomTrip provides excellent namespace support:
// Create elements with namespaces
Element soapEnvelope =
Element.of("soap:Envelope").attribute("xmlns:soap", "http://schemas.xmlsoap.org/soap/envelope/");
// Namespace-aware navigation
String xml =
"""
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<content>Hello</content>
</soap:Body>
</soap:Envelope>
""";
Document doc = Document.of(xml);
Editor editor = new Editor(doc);
Element root = editor.root();
Optional<Element> body = root.child("soap:Body");
if (body.isPresent()) {
System.out.println("Found SOAP body");
}
// Get namespace information
String localName = root.localName();
String namespaceURI = root.namespaceURI();
Configuration Options
Customize DomTrip's behavior with configuration:
String xml = createConfigXml();
Document doc = Document.of(xml);
Editor editor = new Editor(doc);
// Pretty printing
DomTripConfig config = DomTripConfig.prettyPrint();
String prettyXml = editor.toXml(config);
// Minimal output
String minimalXml = editor.toXml(DomTripConfig.minimal());
// Custom configuration
DomTripConfig custom = DomTripConfig.defaults()
.withIndentString(" ") // 2 spaces
.withWhitespacePreservation(true)
.withCommentPreservation(true);
String customXml = editor.toXml(custom);
Real-World Example: Maven POM Editing
Here's a practical example of editing a Maven POM file:
public void addDependencyExample(String pomPath, String groupId, String artifactId, String version)
throws Exception {
// Load POM with automatic encoding detection
Document doc = Document.of(Path.of(pomPath));
Editor editor = new Editor(doc);
// Find or create dependencies section
Element project = editor.root();
Element dependencies = project.descendant("dependencies").orElse(null);
if (dependencies == null) {
dependencies = editor.addElement(project, "dependencies");
}
// Add new dependency
Element dependency = editor.addElement(dependencies, "dependency");
editor.addElement(dependency, "groupId", groupId);
editor.addElement(dependency, "artifactId", artifactId);
editor.addElement(dependency, "version", version);
// Save back to file (String-based)
Files.writeString(Path.of(pomPath), editor.toXml());
// Or save to OutputStream with proper encoding
try (OutputStream outputStream = Files.newOutputStream(Path.of(pomPath))) {
editor.document().toXml(outputStream);
}
System.out.println("✅ Added dependency: " + groupId + ":" + artifactId);
}
Working with Existing Documents
If you already have a parsed Document object, you can create an Editor from it:
// Parse with Document directly
String xmlString = createConfigXml();
Document document = Document.of(xmlString);
// Create Editor from existing Document
Editor editor = new Editor(document);
// Now use the convenient Editor API
Element root = editor.root();
editor.addElement(root, "newChild", "value");
editor.setAttribute(root, "version", "2.0");
// Serialize with preserved formatting
String result = editor.toXml();
You can also use custom configuration with existing documents:
// Create document programmatically
Document doc = Document.withRootElement("project");
// Create Editor with custom config
DomTripConfig config = DomTripConfig.prettyPrint().withIndentString(" ");
Editor editor = new Editor(doc, config);
// Build document structure
Element root = editor.root();
editor.addElement(root, "groupId", "com.example");
editor.addElement(root, "artifactId", "my-project");
Error Handling
DomTrip provides robust error handling:
try {
// Attempt to parse malformed XML
String malformedXml = "<root><unclosed>";
Document doc = Document.of(malformedXml);
// This won't be reached due to parsing error
Editor editor = new Editor(doc);
} catch (Exception e) {
// Handle parsing errors gracefully
System.err.println("XML parsing failed: " + e.getMessage());
// Provide fallback or user-friendly error message
System.out.println("Please check your XML syntax and try again.");
}
// Safe navigation with Optional
String xml = createConfigXml();
Document doc = Document.of(xml);
Editor editor = new Editor(doc);
editor.root()
.descendant("nonexistent")
.ifPresentOrElse(
element -> System.out.println("Found: " + element.name()),
() -> System.out.println("Element not found - using default behavior"));
Next Steps
Now that you've mastered the basics, explore more advanced features:
- 🏗️ Builder Patterns - Fluent APIs for complex XML
- 🌐 Namespace Support - Working with XML namespaces
- ⚙️ Configuration - Customizing DomTrip's behavior
- 📖 Examples - Real-world use cases
Tips for Success
- Always use try-with-resources for file operations
- Check for null when finding elements that might not exist
- Use Optional for safer navigation
- Leverage Stream API for filtering and processing collections
- Configure appropriately for your use case (preserve vs. pretty print)