Source code for triplets.cli.cim_diff
"""
CIM Diff Tool
=============
Command-line tool for comparing CIM XML (Common Information Model) files and
displaying differences in unified diff format.
This tool compares CIM files at the semantic level (object-by-object based on
ID, KEY, VALUE triplets) rather than as plain XML text. This makes it much more
useful for identifying actual data changes while ignoring irrelevant formatting
or ordering differences.
Installation
------------
Install the triplets package::
pip install triplets
Or install from source::
git clone https://github.com/Haigutus/triplets.git
cd triplets
pip install -e .
Using uv (recommended)::
uv pip install -e .
Usage
-----
After installation, the tool can be invoked in three ways:
1. **As a command-line tool** (recommended)::
cim-diff original.xml modified.xml
2. **As a Python module**::
python -m triplets.tools.cim_diff_cli original.xml modified.xml
3. **Programmatically** in Python code::
from triplets import rdf_parser
# Load both files
original = rdf_parser.load_all_to_dataframe(['original.xml'])
modified = rdf_parser.load_all_to_dataframe(['modified.xml'])
# Print diff
rdf_parser.print_triplets_diff(original, modified, exclude_objects=['NamespaceMap', 'Distribution'])
Features
--------
- Semantic comparison at triplet level (ID, KEY, VALUE)
- Unified diff format output for easy reading
- Support for ZIP archives (single or nested)
- Default exclusions for metadata objects (NamespaceMap, Distribution)
- Custom exclusion lists for filtering out specific object types
- Handles large CIM files efficiently
Examples
--------
Basic diff between two CIM files::
$ cim-diff original.xml modified.xml
Diff with custom exclusions::
$ cim-diff original.xml modified.xml -ex Terminal ConnectivityNode
Diff without default exclusions::
$ cim-diff original.xml modified.xml --no-default-exclusions
Diff between ZIP archives::
$ cim-diff original.zip modified.zip
Add custom exclusions on top of defaults::
$ cim-diff original.xml modified.xml -ex CustomType1 CustomType2
Output Format
-------------
The tool outputs differences in unified diff format::
--- Objects in original_file
+++ Objects in modified_file
- ObjectID ObjectType.attribute oldValue
+ ObjectID ObjectType.attribute newValue
Lines starting with '-' indicate values removed (in original but not in modified).
Lines starting with '+' indicate values added (in modified but not in original).
Default Exclusions
------------------
By default, the following object types are excluded from comparison as they
typically contain auto-generated metadata that changes between exports:
- NamespaceMap : XML namespace mappings (contains UUIDs)
- Distribution : File distribution metadata
Use --no-default-exclusions to include these in the comparison.
See Also
--------
cim-spreadsheet : Tool for converting between CIM XML and spreadsheet formats
triplets.rdf_parser.print_triplets_diff : Core diff function
"""
import sys
import argparse
from .. import rdf_parser
[docs]
def main():
"""
CLI entry point for cim-diff tool.
Parses command-line arguments and executes comparison of two CIM XML files,
displaying differences in unified diff format.
Command-Line Usage
------------------
Basic usage::
cim-diff original.xml modified.xml
With custom exclusions::
cim-diff original.xml modified.xml -ex Terminal ACLineSegment
Without default exclusions::
cim-diff original.xml modified.xml --no-default-exclusions
Combined exclusions::
cim-diff original.xml modified.xml -ex CustomType --no-default-exclusions
Parameters
----------
original_file : str (positional)
Path to original CIM XML file or ZIP archive
changed_file : str (positional)
Path to modified CIM XML file or ZIP archive
-ex, --exclude_objects : list of str, optional
Object type names (without namespace/prefix) to exclude from diff.
These are added to default exclusions unless --no-default-exclusions is used.
--no-default-exclusions : flag, optional
Disable default exclusions (NamespaceMap, Distribution)
Exit Codes
----------
0 : Successful comparison (differences shown on stdout)
Notes
-----
The diff is performed on the semantic triplet level (ID, KEY, VALUE),
not on raw XML text. This means:
- XML formatting differences are ignored
- Element ordering differences are ignored
- Only actual data value changes are shown
- Object type filtering happens before comparison
See Also
--------
triplets.rdf_parser.load_all_to_dataframe : Loads CIM XML into triplet format
triplets.rdf_parser.print_triplets_diff : Prints differences between triplet DataFrames
"""
parser = argparse.ArgumentParser(
description="""Create diff in Unified format for XML RDF CIM files.
Diff is per object (ID KEY VALUE) not per XML line in file.
The input can be xml, zip(xml), zip(zip(xml))""",
epilog="""Copyright (c) Kristjan Vilgo 2026; Licence: MIT"""
)
parser.add_argument('original_file', type=str, help='Original file path')
parser.add_argument('changed_file', type=str, help='Changed file path')
parser.add_argument('-ex', '--exclude_objects', nargs='+', help='Names of rdf:Description rdf:type-s without namespace or prefix to be excluded from diff (default: NamespaceMap, Distribution)')
parser.add_argument('--no-default-exclusions', action='store_true', help='Disable default exclusions (NamespaceMap, Distribution)')
args = parser.parse_args()
# Default exclusions (typically objects that change due to UUIDs/metadata)
default_exclusions = ['NamespaceMap', 'Distribution']
# Determine final exclusion list
if args.no_default_exclusions:
exclude_objects = args.exclude_objects
else:
# Combine default exclusions with user-provided ones
exclude_objects = default_exclusions.copy()
if args.exclude_objects:
exclude_objects.extend(args.exclude_objects)
# Load and compare files
original_data = rdf_parser.load_all_to_dataframe([args.original_file])
changed_data = rdf_parser.load_all_to_dataframe([args.changed_file])
rdf_parser.print_triplets_diff(original_data, changed_data, exclude_objects=exclude_objects if exclude_objects else None)
if __name__ == "__main__":
main()