Registry / serialization / xmldiff

xmldiff

JSON →
library3.0pypypi✓ verified 85d ago

xmldiff is a Python library and command-line utility designed to create semantic differences between XML files. Unlike traditional line-by-line diff tools, it focuses on identifying structural and content changes in hierarchical XML data, often generating human-readable diffs. It is currently at version 2.7.0 and is under active development, though the library explicitly states that output formats and edit scripts might change between versions due to ongoing improvements.

pip install xmldiff
INSTALL
IMPORT
SIG · XMLDIFF
X
xmldiff
serializationpythonv3.0
Install
2.3s avg
Import
174ms
Disk
31MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v3.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.920 runs
installs and imports cleanly · install 0.0s · import 0.182s · 30MB
glibc
py 3.103.920 runs
installs and imports cleanly · install 2.3s · import 0.166s · 30MB
31MB installed
● package 31MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

main
from xmldiff import main
Provides the primary diffing functions like `diff_files`, `diff_texts`, `diff_trees`, and `patch_file`.
formatting
from xmldiff import formatting
Contains built-in formatters like `XMLFormatter` for controlling output style.
etree
from lxml import etree
Essential for creating and manipulating XML tree objects when using `diff_trees` or processing formatter output.

This quickstart demonstrates how to use `xmldiff` to compare two XML files. It creates two temporary XML files, then calls `main.diff_files()` with `formatting.XMLFormatter` to get a human-readable XML output with differences marked. It also shows how to get the raw 'edit script' (list of actions) by calling `main.diff_trees()` with `lxml` Element objects directly.

import os from lxml import etree from xmldiff import main, formatting # Create dummy XML files xml1_content = """ <root> <item id="1">Value A</item> <item id="2">Value B</item> </root> """ xml2_content = """ <root> <item id="1">Value A - Changed</item> <item id="3">Value C</item> <item id="2" status="new">Value B</item> </root> """ with open('file1.xml', 'w') as f: f.write(xml1_content) with open('file2.xml', 'w') as f: f.write(xml2_content) # Diff two XML files and format the output as XML with diff tags diff_output_xml = main.diff_files( 'file1.xml', 'file2.xml', formatter=formatting.XMLFormatter(pretty_print=True) ) print("--- XML Diff ---") print(diff_output_xml) # Clean up dummy files os.remove('file1.xml') os.remove('file2.xml') # Example using diff_trees with lxml elements directly tree1 = etree.fromstring(xml1_content) tree2 = etree.fromstring(xml2_content) diff_actions = main.diff_trees(tree1, tree2) print("\n--- Edit Script (List of Actions) ---") for action in diff_actions: print(action)
xmldiff --version
Debug
Known issues
breakingxmldiff 2.0 introduced a complete, ground-up rewrite of the library. This change included a new API, different output formats, and was initially significantly slower than previous 0.x/1.x versions. Code written for 0.x/1.x is incompatible with 2.x and later.
fix
Review the official documentation for xmldiff 2.x and rewrite code to use the new API, particularly `main.diff_files`, `diff_texts`, `diff_trees`, and `formatting` modules.
affects: 2.0.0 and later
gotchaThe `xmldiff` library expects `lxml` ElementTree instances when using functions like `diff_trees()`. Passing standard `xml.etree.ElementTree` objects will result in errors or unexpected behavior, requiring conversion to `lxml` types first.
fix
Ensure that any XML trees passed to `xmldiff` functions are `lxml.etree._Element` or `lxml.etree._ElementTree` objects. Convert from `xml.etree` if necessary, e.g., by parsing XML strings directly with `lxml.etree.fromstring` or `lxml.etree.parse`.
affects: All 2.x versions
gotchaThe output (edit script or formatted XML) generated by `xmldiff` can change between minor versions. The library explicitly states that there are 'no guarantees' the output will be the same across versions, as it's under 'rapid development'. This means automated tests relying on exact output matches may break.
fix
When writing tests or parsers for `xmldiff` output, focus on the semantic correctness of the changes rather than exact string or action sequence matches. Consider flexible parsing or asserting on the presence/absence of expected changes rather than full output equality.
affects: All 2.x versions
gotchaPrior to version 2.6, `xmldiff` had limited or buggy handling of XML namespaces, potentially leading to 'Unknown namespace prefix' errors. While improved in 2.6, changing the URI of an existing namespace prefix is still not supported and will raise an error.
fix
Upgrade to `xmldiff` version 2.6.0 or higher for improved namespace handling. Avoid scenarios where a namespace prefix's URI is changed between the two XML documents; instead, ensure prefixes map to consistent URIs or handle such cases manually before diffing.
affects: < 2.6.0 (Namespace bugs), All versions (Changing URI for prefix)
gotchaThe `ratio-mode` (`accurate`, `faster`, `fast`) and `--fast-match` options can significantly impact the diff's accuracy and performance. The `fast` mode, in particular, yields less accurate results, which might be acceptable for speed but could miss subtle changes.
fix
Understand the trade-offs between performance and accuracy when selecting `ratio-mode` or `--fast-match`. For critical diffing where every change must be detected, use `accurate` mode. For large files where an approximate diff is sufficient, faster modes can be considered, but be aware of potential missed details.
affects: All 2.x versions
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'xmldiff'
The 'xmldiff' package has not been installed in the active Python environment.
fix
pip install xmldiff
ImportError: cannot import name 'diff_texts' from 'xmldiff'
The main diffing functions like 'diff_texts' and 'diff_files' are located within the 'xmldiff.main' submodule, not directly under the top-level 'xmldiff' package.
fix
from xmldiff.main import diff_texts
TypeError: diff_texts() missing 1 required positional argument: 'b'
The 'diff_texts' (or 'diff_files') function requires two XML inputs (the old and new versions) for comparison, but only one or none was provided.
fix
diff_texts(old_xml_string, new_xml_string)
lxml.etree.XMLSyntaxError: Document is empty
The input provided to xmldiff's functions (e.g., diff_texts, diff_files) is not valid or well-formed XML, or is an empty string/file, which lxml cannot parse.
fix
Ensure that the input strings or files contain valid, non-empty, and well-formed XML documents.
Upgrade
Version history
3.0latest on PyPI · released Jun 11, 2026
Audit
Dependencies
lxmlrequiredRequired for parsing and manipulating XML trees, central to xmldiff's functionality.
diff-match-patchoptionalOptional dependency for faster text comparisons in certain scenarios.
Agent activity
45 hits · last 30 days
node
38
OpenAI (training)
1
Resources
xmldiff — pip install xmldiff · libregistry