| Crates.io | xml-3dm |
| lib.rs | xml-3dm |
| version | 0.1.0 |
| created_at | 2025-11-26 21:47:30.415427+00 |
| updated_at | 2025-11-26 21:47:30.415427+00 |
| description | 3-way XML diff and merge tool |
| homepage | https://github.com/06chaynes/3dm-rs |
| repository | https://github.com/06chaynes/3dm-rs |
| max_upload_size | |
| id | 1952417 |
| size | 376,124 |
A Rust implementation of the 3DM (3-way Diff/Merge) algorithm for structure-aware XML differencing and merging.
xml-3dm is a library for performing 3-way merges on XML documents. The library operates on XML tree structure and handles the following scenarios:
This is a Rust port of the original 3DM tool created by Tancred Lindholm as part of his Master's thesis at Helsinki University of Technology.
Add this to your Cargo.toml:
[dependencies]
xml-3dm = "0.1"
use xml_3dm::{parse_file, BaseNodeFactory, BranchNodeFactory, XmlParser, Merge, TriMatching};
use std::io;
// Parse the three XML files
let base_parser = XmlParser::new(BaseNodeFactory);
let branch_parser = XmlParser::new(BranchNodeFactory);
let base = base_parser.parse_file("base.xml")?;
let left = branch_parser.parse_file("branch1.xml")?;
let right = branch_parser.parse_file("branch2.xml")?;
// Build matching between the three trees
let matching = TriMatching::new(left, base, right);
// Perform the merge
let mut merger = Merge::new(matching);
merger.merge(&mut io::stdout())?;
// Check for conflicts
if merger.conflict_log.has_conflicts() {
eprintln!("Conflicts detected:");
for conflict in merger.conflict_log.conflicts() {
eprintln!(" {}", conflict);
}
}
use xml_3dm::{parse_file, BaseNodeFactory, BranchNodeFactory, XmlParser, Diff, DiffMatching};
use std::io;
// Parse base and modified versions
let base_parser = XmlParser::new(BaseNodeFactory);
let branch_parser = XmlParser::new(BranchNodeFactory);
let base = base_parser.parse_file("base.xml")?;
let branch = branch_parser.parse_file("modified.xml")?;
// Build matching optimized for diff
let matching = DiffMatching::new(base, branch);
// Generate diff
if let Some(diff) = Diff::new(&matching) {
diff.diff(&mut io::stdout())?;
}
use xml_3dm::{parse_file, BaseNodeFactory, XmlParser, Patch};
use std::io;
// Parse base and diff
let parser = XmlParser::new(BaseNodeFactory);
let base = parser.parse_file("base.xml")?;
let diff = parser.parse_file("changes.xml")?;
// Apply patch
let patcher = Patch::new();
patcher.patch(&base, &diff, &mut io::stdout())?;
The 3DM algorithm works in several phases:
The minimum size (in information bytes) for copy detection can be configured:
use xml_3dm::TriMatching;
// Disable copy detection
let matching = TriMatching::with_copy_threshold(left, base, right, 0);
// Increase threshold (default is 128)
let matching = TriMatching::with_copy_threshold(left, base, right, 256);
You can provide custom matching implementations:
use xml_3dm::{TriMatching, HeuristicMatching};
let left_matching = HeuristicMatching::new(128);
let right_matching = HeuristicMatching::new(128);
let matching = TriMatching::with_matching(
left,
base,
right,
left_matching,
right_matching,
);
Licensed under the GNU Lesser General Public License v2.1 or later (LGPL-2.1-or-later), matching the original 3DM implementation.
Original 3DM implementation by Tancred Lindholm (Helsinki University of Technology, 2001).