https://github.com/chemodun/x4-xmldiffandpatch
This toolset is a simple XML diff and patch tools for X4: Foundations. It is designed to help modders to compare and patch XML files. The format of diff XML files is compatible with the appropriate `diff.xsd` format definition.
https://github.com/chemodun/x4-xmldiffandpatch
egosoft x4 x4foundations xml xmldiff xmlpatch
Last synced: about 1 month ago
JSON representation
This toolset is a simple XML diff and patch tools for X4: Foundations. It is designed to help modders to compare and patch XML files. The format of diff XML files is compatible with the appropriate `diff.xsd` format definition.
- Host: GitHub
- URL: https://github.com/chemodun/x4-xmldiffandpatch
- Owner: chemodun
- License: other
- Created: 2025-01-15T16:21:25.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2026-05-26T10:01:17.000Z (about 1 month ago)
- Last Synced: 2026-05-26T11:17:58.660Z (about 1 month ago)
- Topics: egosoft, x4, x4foundations, xml, xmldiff, xmlpatch
- Language: C#
- Homepage:
- Size: 327 KB
- Stars: 3
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: Docs/README.egosoft
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
[size=140][u]Modding tools: XML diff and patch for X4: Foundations[/u][/size]
This toolset is a simple XML diff and patch tools for X4: Foundations. It is designed to help modders to compare and patch XML files.
The format of diff XML files is compatible with the appropriate [b]diff.xsd[/b] format definition. It is means - you can you this tool to create diff files for any XML files used in game.
Also, you can use appropriate tool to patch XML files with diff files, this action has reason to check how your diff file will be applied to the vanilla XML file. Or better understand, what other modders did in their mods.
[size=130][u]Important note[/u][/size]
It is highly recommended to use the [b]diff.xsd[/b] file to validate the diff XML files. It is especially important when you creating them by [b]XMLDiff.exe[/b].
But there is one [b]significant limitation[/b] of the current version of the [b]diff.xsd[/b] file (distributed with game version 8.00HF3/4)- it has strict rules for the [b]replace[/b] operation. It has to support only one element in the [b]replace[/b] element. It is means - if your files have more than one element in the [b]replace[/b] element, the validation will fail. So, not use the [b]diff.xsd[/b] file for validation in this case at all.
If the [b]diff.xsd[/b] file if it located in the "current" folder it will be used automatically. If you want to use another [b]diff.xsd[/b] file, you can specify it with the [b]-x[/b] option.
[size=130][u]How to use[/u][/size]
[list]
[*] Download the latest release from:
[list]
[*] GitHub [url=https://github.com/chemodun/X4-XMLDiffAndPatch/releases/]releases page[/url] - there is an archive file [b]XMLDiffAndPatch.zip[/b].
[*] [url=https://www.nexusmods.com/x4foundations/mods/1578]NexusMods[/url] - there is an archive file [b]XMLDiffAndPatch.zip[/b].
[/list]
[*] Extract the archive file to any useful location.
[*] Inside will be a folder named [b]XMLDiffAndPatch[/b] with two executables - [b]XMLDiff.exe[/b] and [b]XMLPatch.exe[/b].
[/list]
[size=125][u]How to create a diff file[/u][/size]
There is a command line help for the [b]XMLDiff[/b] tool:
[code=shell]
XMLDiff 1.2.1
Developed by Chem O`Dun
-o, --original_xml Required. Original XML file or directory.
-m, --modified_xml Required. Modified XML file or directory.
-d, --diff_xml Required. Output diff file or directory.
-x, --xsd Path to diff.xsd (default: diff.xsd).
-l, --log-to-file Enable file logging at the specified level: error|warn|info|debug. Console always logs at info level.
-a, --append-to-log (Default: false) Append to existing log file instead of overwriting.
--only-full-path (Default: false) Generate only full absolute XPath (no // shorthand).
--use-all-attributes (Default: false) Include all attributes in XPath predicates.
--ignore-diff-in-attribute Attribute name to ignore when comparing elements.
--compact-path (Default: false) When an element name is not unique within its parent, prefer
path continuation through a child element over adding attributes at the current
level. When name alone is already unique, no attributes are added either.
--qualified-path (Default: false) Always include at least the first attribute in XPath steps,
even when the element name alone is already unique within its parent.
--help Display this help screen.
--version Display version information.
[/code]
Example:
[code=shell]
XMLDiff.exe -o vanilla.xml -m modified.xml -d diff.xml
[/code]
[size=125][u]Example of resulting diff files[/u][/size]
There the is example of the diff files created by tool:
[list]
[*] with add operation:
[/list]
[code=xml]
[/code]
[list]
[*] with replace operation:
[/list]
[code=xml]
@$speak and not this.assignedcontrolled.nextorder and (@$defaultorder.id != 'ProtectSector') and (@$defaultorder.id != 'Patrol') and (@$defaultorder.id != 'ProtectPosition') and (@$defaultorder.id != 'ProtectShip') and (@$defaultorder.id != 'ProtectStation') and (@$defaultorder.id != 'Plunder') and (@$defaultorder.id != 'Police') and (not this.assignedcontrolled.commander or (this.assignedcontrolled.commander == player.occupiedship)) and notification.npc_await_orders.active
[/code]
[size=120][u]Path options[/u][/size]
[size=115][u]Default: [b]//[/b] shorthand when globally unique[/u][/size]
By default the tool uses the [b]//[/b] XPath shorthand when an element is globally unique in the document, producing shorter and more readable [b]sel[/b] paths.
Example:
[code=xml]
...
[/code]
[size=115][u][b]--only-full-path[/b]: always use full absolute path[/u][/size]
The [b]--only-full-path[/b] option forces the tool to always generate a full path (starting from [b]/rootElement/...[/b]) and never use the [b]//[/b] shorthand.
Example:
[code=xml]
[/code]
[size=115][u]Attribute predicates in XPath steps[/u][/size]
By default, XPath steps are generated with the minimum number of attributes needed for uniqueness:
[list]
[*] If an element name is already unique within its parent, no attributes are added — the name alone is used.
[*] If the name is not unique, attributes are added one by one until uniqueness is achieved.
[*] If no combination of attributes makes the element unique at its level, a child-element predicate is used as a last resort.
[/list]
This keeps [b]sel[/b] paths short while remaining unambiguous in the given source XML.
[size=115][u]Use all attributes in XPath[/u][/size]
The [b]--use-all-attributes[/b] option forces all attributes of an element to be included in its XPath predicate, regardless of uniqueness. Useful when maximum specificity is preferred.
Example:
[code=xml]
[/code]
[size=115][u]Ignore differences in the specified attribute[/u][/size]
The [b]--ignore-diff-in-attribute[/b] option will ignore differences in the specified attribute when comparing elements. It is useful when you want to ignore differences in attributes like [b]version[/b], [b]comment[/b], etc.
[size=115][u][b]--compact-path[/b]: prefer child-path continuation when not unique[/u][/size]
The [b]--compact-path[/b] option changes how the tool resolves ambiguity when an element name is not unique within its parent. Instead of immediately adding attributes at the current level, it first tries to continue the path through the on-path child element (producing [b]parent/child[@attr]/...[/b] rather than [b]parent[@attr]/child[@attr]/...[/b]). When the name is already unique, no attributes are added, same as the default. If neither the child path nor any attributes achieve uniqueness, it falls back to the standard sibling-index mechanism.
[size=115][u][b]--qualified-path[/b]: always include at least the first attribute[/u][/size]
[quote][b]Note:[/b] This option replaces [b]--human-readable[/b] from v1.2.0, which has been removed.[/quote]
The [b]--qualified-path[/b] option forces every XPath step to include at least the first attribute of the element, even when the element name alone is already unique within its parent. Additional attributes are still added only as needed for uniqueness. This produces more descriptive [b]sel[/b] paths that remain valid even if siblings with the same name are added to the source XML in the future.
[size=120][u]Defining the position generation for the diff by in-line comment[/u][/size]
The [b]pos[/b] attribute of the [b]add[/b] is usually set to [b]after[/b], taking in account the common logic of how the program is working. But in some cases, you may want to have a diff file with the [b]pos[/b] attribute set to [b]before[/b]. Mostly it is useful when working in conjunction with VS Code.
You can define the position of the [b]add[/b] element in the diff file by using an in-line comment in the original XML file. The comment should be placed before the element you want to add and should contain the text [b][/b].
[size=125][u]How to apply a diff file[/u][/size]
There is a command line help for the [b]XMLPatch[/b] tool:
[code=shell]
XMLPatch 1.2.1
Developed by Chem O`Dun
-o, --original_xml Required. Path to the original XML file or directory.
-d, --diff_xml Required. Path to the diff XML file or directory.
-u, --output_xml Required. Path for the output XML file or directory.
-x, --xsd Path to diff.xsd (default: diff.xsd).
-l, --log-to-file Enable file logging at the specified level: error|warn|info|debug. Console always logs at info level.
-a, --append-to-log (Default: false) Append to existing log file instead of overwriting.
--allow-doubles (Default: false) Skip duplicate-element guard when applying operations.
--help Display this help screen.
--version Display version information.
[/code]
Example:
[code=shell]
XMLPatch.exe -o vanilla.xml -d diff.xml -u modified.xml
[/code]
[size=125][u]Example of resulting patched XML files[/u][/size]
There is an example of the patched XML files created by the tool:
[list]
[*] with add operation:
[/list]
[code=xml]
[/code]
[list]
[*] with replace operation:
[/list]
[code=xml]
[/code]
[size=125][u]If output XML is a directory[/u][/size]
If the output XML is a directory, the tool will create a new XML file with the same name as the original XML file in the output directory.
For example, if the original XML file is [b]vanilla.xml[/b] and the output directory is [b]output[/b], the tool will create a new XML file [b]output/vanilla.xml[/b].
[size=125][u]How to apply the tools to directories[/u][/size]
[size=120][u]Applying XMLDiff to directories[/u][/size]
You can apply the XMLDiff tool to directories. In this case, the tool will traverse the directory structure and create diff files for XML files with identical names and relative paths. The process is as follows:
[list]
[*] If all input parameters are directories, the tool will create diff files for all XML files in the directories.
[*] The tool will recursively go through the directory structure, using modified files as a "key" for it.
[*] For each changed file, the corresponding original XML file in the original directory with the same relative path will be checked.
[*] If the original XML file is not found, the operation will be skipped.
[*] If the original XML file is found, the diff file will be created in the output directory with the same relative path.
[/list]
Example:
[code=shell]
XMLDiff.exe -o vanilla_dir -m modified_dir -d diff_dir
[/code]
[size=120][u]Applying XMLPatch to directories[/u][/size]
You can apply the XMLPatch tool to directories. In this case, the tool will traverse the directory structure and apply the patch to XML files with identical names and relative paths. The process is as follows:
[list]
[*] If all input parameters are directories, the tool will apply the patch to all XML files in the directories.
[*] The tool will recursively go through the directory structure, using diff files as a "key" for it.
[*] For each diff file, the corresponding original XML file in the original directory with the same relative path will be checked.
[*] If the original XML file is not found, the operation will be skipped.
[*] If the original XML file is found, the diff file will be patched with the original XML file, and a new patched XML file will be created in the output directory with the same relative path.
[/list]
Example:
[code=shell]
XMLPatch.exe -o vanilla_dir -d diff_dir -u modified_dir
[/code]
[size=130][u]Issues reporting[/u][/size]
If you have any issues with the tool, please create an issue on the [url=https://github.com/chemodun/x4_XMLDiffAndPatch/issues]issues page[/url].
It will be highly appreciated if you provide the version of the used tool and the [b]XMLDiff.log[/b] or [b]XMLPatch.log[/b] file respectively.
To create such a log file, use the [b]-l[/b] option with the [b]debug[/b] level, e.g. [b]-l debug[/b]. The console output is always at [b]info[/b] level; detailed debug information is written only to the file.
[size=130][u]License[/u][/size]
This tool is licensed under the Apache License, Version 2.0. You can find it in the [url=https://github.com/chemodun/X4-XMLDiffAndPatch/raw/main/LICENSE]LICENSE[/url] file.
[size=130][u]Credits[/u][/size]
Special thanks to [url=https://forum.egosoft.com/memberlist.php?mode=viewprofile&u=419622]Duncaroos[/url] for the patience, testing, and valuable feedback.
[size=130][u]Additional links[/u][/size]
There is a topic on the [url=https://forum.egosoft.com/viewtopic.php?t=468623]EGOSOFT forum[/url], related to this toolset.
The toolset is also available as a [url=https://marketplace.visualstudio.com/items?itemName=X4DevTools.xmldiffandpatch]VS Code extension[/url] on the Visual Studio Marketplace, providing the same diff and patch functionality directly inside VS Code.
[size=130][u]Antivirus scanning[/u][/size]
Please be aware - each release archive has an appropriate link to the [url=https://www.virustotal.com]VirusTotal[/url]. Follow the link to be sure that the archive is safe.
[size=130][u]Changelog[/u][/size]
[size=125][u][1.2.1] - 2026-05-27[/u][/size]
[list]
[*] Changed:
[list]
[*] XMLDiff: default XPath generation reverted to minimal mode — no attributes are added when the element name alone is unique within its parent.
[*] XMLDiff: [b]--compact-path[/b] enhanced — when name is not unique, now prefers child-path continuation ([b]parent/child[@attr]/...[/b]) over adding attributes at the current level before falling back to attributes.
[*] XMLDiff: [b]--human-readable[/b] (added in v1.2.0) replaced by [b]--qualified-path[/b] — always includes at least the first attribute in XPath steps even when the element name alone is sufficient.
[/list]
[*] Added:
[list]
[*] XMLDiff: [b]--qualified-path[/b] option — always include at least the first attribute in XPath steps, even when the element name alone is already unique within its parent.
[/list]
[/list]
[size=125][u][1.2.0] - 2026-05-27[/u][/size]
[list]
[*] Fixed:
[list]
[*] XMLDiff: unpaired deleted/inserted elements (different names) now produce [b]replace[/b] operations instead of separate [b]remove[/b]/[b]add[/b] pairs.
[*] XMLDiff: attribute difference counting in element matching — elements with two or more differing attributes were incorrectly treated as close-enough matches for pairing.
[/list]
[*] Improved:
[list]
[*] XMLDiff: sibling XPath expressions now use globally-unique [b]//[/b] anchors where applicable, producing shorter and more readable [b]sel[/b] paths (unless [b]--only-full-path[/b] is set).
[*] XMLDiff: elements without own attributes are now qualified using a child-existence predicate (e.g. [b]do_else[do_if[@value='...']][/b]) to avoid numeric position indices, preferring the child element that lies on the path to the target.
[*] XMLDiff: when the on-path child alone can qualify a parent element, the natural path form [b]parent/child[@attr][/b] is preferred over the redundant predicate form [b]parent[child[@attr]]/child[@attr][/b].
[/list]
[*] Added:
[list]
[*] XMLDiff: [b]--human-readable[/b] option — always includes at least the first attribute in XPath steps, making [b]sel[/b] paths easier to read even when the element name alone would suffice. [i](Replaced by [b]--qualified-path[/b] in v1.2.1.)[/i]
[/list]
[/list]
[size=125][u][1.1.1] - 2026-05-26[/u][/size]
[list]
[*] Improved:
[list]
[*] XPath generation is now more namespace independent
[*] XPath generation focuses on avoiding numerical indices in paths as much as possible, including fallback to the full path
[/list]
[/list]
[size=125][u][1.1.0] - 2026-05-17[/u][/size]
[list]
[*] Improved:
[list]
[*] XMLDiff: implement LCS-based child comparison and edit processing
[/list]
[/list]
[size=125][u][1.0.5] - 2026-05-17[/u][/size]
[list]
[*] Improved:
[list]
[*] XMLDiff: enhance matching logic for original and modified elements
[/list]
[/list]
[size=125][u][1.0.4] - 2026-05-16[/u][/size]
[list]
[*] Fixed:
[list]
[*] XMLDiff: attribute comparison logic
[/list]
[/list]
[size=125][u][1.0.3] - 2026-05-15[/u][/size]
[list]
[*] Fixed:
[list]
[*] Single attribute change handling.
[*] Text nodes comparison.
[/list]
[/list]
[size=125][u][1.0.2] - 2026-05-15[/u][/size]
[list]
[*] Improved:
[list]
[*] Logging.
[/list]
[/list]
[size=125][u][1.0.1] - 2026-05-15[/u][/size]
[list]
[*] Improved:
[list]
[*] Full internal rewrite.
[/list]
[/list]
[size=125][u][0.2.31] - 2026-05-15[/u][/size]
[list]
[*] Fixed:
[list]
[*] XMLDiff: [b]replace[/b]/[b]remove[/b] operation detection logic for attributes
[/list]
[/list]
[size=125][u][0.2.30] - 2026-05-15[/u][/size]
[list]
[*] Fixed:
[list]
[*] XMLDiff: [b]replace[/b]/[b]remove[/b] operation detection logic
[/list]
[/list]
[size=125][u][0.2.29] - 2026-03-02[/u][/size]
[list]
[*] Improved:
[list]
[*] XMLDiff: [b]replace[/b] operation detection logic
[/list]
[/list]
[size=125][u][0.2.28] - 2026-02-22[/u][/size]
[list]
[*] Improved:
[list]
[*] XMLDiff and XMLPatch: added possibility to process multi-line [b]replace[/b] diff elements.
[/list]
[/list]
[size=125][u][0.2.27] - 2025-08-28[/u][/size]
[list]
[*] Improved:
[list]
[*] XMLDiff: added --ignore-diff-in-attribute option to ignore differences in the specified attribute when comparing elements. It is useful when you want to ignore differences in attribute [b]version[/b] in X4 script files.
[/list]
[/list]
[size=125][u][0.2.26] - 2025-06-16[/u][/size]
[list]
[*] Improved:
[list]
[*] XMLDiff: added in-line comments processing for the [b]add[/b] elements in the modified XML file. It allows to define the position attribute of the [b]add[/b] element in the diff file.
[/list]
[/list]
[size=125][u][0.2.25] - 2025-03-31[/u][/size]
[list]
[*] Fixed:
[list]
[*] XMLDiff: fixed issue missed root element attributes comparison
[*] XMLDiff: fixed usage of the removed element path for the further diff operations
[*] XMLDiff: fixed incorrect index number when addressing the elements in XPath
[*] XMLDiff: fixed identification elements via [b]sibling[/b] keyword in XPath
[/list]
[/list]
[size=125][u][0.2.24] - 2025-03-17[/u][/size]
[list]
[*] Improved:
[list]
[*] Both utilities: result folder will be created in recursive processing as it made now for the single file.
[*] XMLDiff: sibling keyword usage in XPath for the elements.
[*] XMLDiff: XPath generation when the element has child elements, which can unique identify it.
[/list]
[*] Changed:
[list]
[*] XMLDiff: --only-full-path option replaced by --anywhere-is-allowed. And default behavior is to use full path.
[*] Both utilities: log level of console will not be more detailed than for the log file.
[*] Both utilities: the unknown options will be ignored.
[/list]
[*] Fixed:
[list]
[*] XMLDiff: doubling the first attribute in XPath for the elements, if more than one attribute is used.
[/list]
[/list]
[size=125][u][0.2.23] - 2025-03-15[/u][/size]
[list]
[*] Fixed:
[list]
[*] XMLDiff: fixed issue with the last sub element comparison (index out of range)
[/list]
[/list]
[size=125][u][0.2.22] - 2025-03-10[/u][/size]
[list]
[*] Improved
[list]
[*] XMLDiff: The first attribute of elements in XPath will be always added to make a diff more clear.
[*] XMLDiff: If one attribute is not enough to define the element, the next one will be added to the XPath, iteratively.
[*] XMLDiff: Added the [url=https://github.com/chemodun/X4-XMLDiffAndPatch/raw/main/forVSCode/XMLDIffwithVSCode.md]short description of integration with VSCode[/url] via RunXMLDiff.bat script and appropriate extension to make a diffs "on the fly" during editing XML files (modified ones).
[/list]
[/list]
[size=125][u][0.2.21] - 2025-03-03[/u][/size]
[list]
[*] Fixed
[list]
[*] XMLDiff: fixed issue with text nodes differing
[*] XMLDiff: improved "pos" definition logic
[*] XMLDiff: improved logging information
[/list]
[*] Added
[list]
[*] XMLPatch: added --allow-doubles option, useful for scripts patching
[*] XMLPatch: added comments processing, now comments will be added to the resulting XML file
[/list]
[/list]
[size=125][u][0.2.20] - 2025-02-27[/u][/size]
[list]
[*] Fixed
[list]
[*] XMLDiff: wrong attribute selection for the path
[*] XMLDiff: fixed issue with not applied --append-to-log option
[*] XMLDiff: fixed issue with wrong changed attributes count detection
[*] XMLDiff: fixed usage or remove/add instead of replace for elements
[*] XMLPatch: skip the diff file without diff elements
[/list]
[*] Improved
[list]
[*] Both utilities: --log-to-file option now requires a log level (error, warn, info, debug) as a parameter
[/list]
[/list]
[size=125][u][0.2.17] - 2025-02-25[/u][/size]
[list]
[*] Fixed
[list]
[*] Added checks to prevent duplicate elements during addition
[/list]
[/list]
[size=125][u][0.2.16] - 2025-02-25[/u][/size]
[list]
[*] Fixed
[list]
[*] Fixed issue with element replacements
[/list]
[*] Improved
[list]
[*] Logging information
[/list]
[/list]
[size=125][u][0.2.15] - 2025-02-24[/u][/size]
[list]
[*] Fixed
[list]
[*] Fixed loading the diff.xsd
[*] Fixed issue, if resulting file has to be located in current folder
[/list]
[*] Improved
[/list] Logging information, especially about wrong sel value. More info logged about processed XML elements.
[list][*] Added
[list]
[*] Possibility to append into existing debug log
[/list]
[/list]
[size=125][u][0.2.14] - 2025-01-17[/u][/size]
[list]
[*] Added
[list]
[*] First public version coded in C#.
[/list]
[/list]