Do you need to compare the differences between versions of generated XML, JSON, etc (e.g. WSDL files from Spring WS, OpenAPI JSON files generated by springdoc-openapi)? The generally unpredictable order often hinders this endeavor, showing a plethora of changes in differencing tools when only a few values have actually changed. Fortunately, Lt. Peacock's Multisorter has you covered.
This library/tool provides the ability to sort various file types.
JDK 8 is required at a minimum.
To build the project as a single executable JAR:
mvn clean package -Pcli
For those who do not want to build it manually, lp-multisorter-cli.jar can be downloaded from most of the releases for direct use.
To see instructions on usage:
java -jar lp-multisorter.jar
This project is also available as a Maven artifact. Maven users can include the library with the following dependency in pom.xml:
<dependency>
<groupId>com.lt-peacock</groupId>
<artifactId>lp-multisorter</artifactId>
<version>1.3.0</version>
</dependency>
With this tool, you can sort both elements and their attributes by name to facilitate comparing with differencing tools.
java -cp lp-multisorter.jar XMLSorter [inputFile] [outputFile]
The command above reads an XML file at the location specified by inputFile
and outputs the sorted result to the location specified by outputFile
. Elements are sorted lexicographically by node name and then by the "name"
attribute, and their attributes are sorted lexicographically by name.
If outputFile
is not specified, output goes to stdout; if inputFile
is also not specified, input is taken from stdin.
Example:
java -cp lp-multisorter.jar XMLSorter file.xml file_sorted.xml
Example with a Unix pipeline:
cat file.xml | java -cp lp-multisorter.jar XMLSorter > file_sorted.xml
Construct a SortXMLEngine
:
SortXMLEngine engine = new SortXMLEngine();
By default, ElementComparator
is used to order elements, which sorts lexicographically by node name and then by the "name"
attribute, and AttributeComparator
is used to order attributes, which sorts lexicographically by attribute name.
To specify a custom order, pass two more arguments to the constructor: a Comparator
for ElementVO
objects and a Comparator
for ElementAttribute
objects. Use ElementComparator.MAINTAIN_ORDER
to keep the original order of elements in the file and AttributeComparator.MAINTAIN_ORDER
to keep the original order of attributes on each element.
SortXMLEngine engine = new SortXMLEngine(elementComparator, attributeComparator);
Then, call sort
with an InputStream
to read the file from and an OutputStream
to write the sorted result to.
engine.sort(new FileInputStream("file.xml"), new FileOutputStream("file_sorted.xml"));
java -cp lp-multisorter.jar JSONSorter [inputFile] [outputFile]
This reads a JSON file at the location specified by inputFile and writes the sorted result to the location specified by outputFile. The sorting is done by rearranging all the keys in each object in lexicographic order. Elements of arrays are not moved around.
If outputFile
is not specified, output goes to stdout; if inputFile
is also not specified, input is taken from stdin.
Construct a SortJSONEngine
. An optional Comparator<String>
can be specified as the first argument to order the keys in each object. By default, the engine sorts keys in lexicographic order.
SortJSONEngine engine = new SortJSONEngine();
Then, call sort
with an InputStream
and an OutputStream
.
engine.sort(new FileInputStream("file.json"), new FileOutputStream("file_sorted.json"));
sort
may also be called with a com.github.openjson.JSONObject
or com.github.openjson.JSONArray
as the only argument, which will sort the keys of all objects in the structure in place.
JSONObject obj = new JSONObject("{\"b\":1,\"a\":2}");
engine.sort(obj);
Like with XML, Lt. Peacock's Multisorter can be used to sort OpenAPI JSON for easy comparison, especially for large files.
java -cp lp-multisorter.jar OpenApiJSONSorter [inputFile] [outputFile]
The command above reads an OpenAPI JSON file at the location specified by inputFile
and outputs the sorted result to the location specified by outputFile
.
If outputFile
is not specified, output goes to stdout; if inputFile
is also not specified, input is taken from stdin.
Construct a SortOpenApiJSONEngine
:
SortOpenApiJSONEngine engine = new SortOpenApiJSONEngine();
Then, call sort
with an InputStream
to read the file from and an OutputStream
to write the sorted result to.
engine.sort(new FileInputStream("file.json"), new FileOutputStream("file_sorted.json"));