Skip to content

Commit

Permalink
XMLSorter and associated classes.
Browse files Browse the repository at this point in the history
  • Loading branch information
LieutenantPeacock committed Oct 2, 2018
1 parent ec6ef32 commit 0b46abe
Show file tree
Hide file tree
Showing 7 changed files with 449 additions and 0 deletions.
116 changes: 116 additions & 0 deletions src/main/java/XMLSorter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import static java.lang.String.format;
import static com.ltpeacock.sorter.xml.Util.logException;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.ltpeacock.sorter.xml.SortXmlEngine;

/**
*
* @author LieutenantPeacock
*
*/
public class XMLSorter {
private static final Logger LOG = Logger.getLogger(XMLSorter.class.getName());

public static void main(String[] args) {
switch (args.length) {
case 2:
fileInFileOut(args[0], args[1]);
break;
case 1:
if ("--help".equals(args[0])) {
help();
} else {
fileInStdOut(args[0]);
}
break;
case 0:
stdInStdOut();
break;
default:
System.err.println("Too many arguments.");
break;
}
}

protected static void fileInFileOut(final String inFileName, final String outFileName) {
final File inFile = new File(inFileName);
final File outFile = new File(outFileName);
final long startMs = System.currentTimeMillis();
boolean success = false;
try (InputStream is = new FileInputStream(inFile);
OutputStream os = new FileOutputStream(outFile)) {
System.out.println(format("Reading from '%s' ...", inFile));
SortXmlEngine engine = new SortXmlEngine();
engine.sort(is, os);
success = true;
} catch (FileNotFoundException e) {
logException(e);
} catch (IOException e) {
logException(e);
}
if (success) {
final long endMs = System.currentTimeMillis();
final long tookMs = endMs - startMs;
System.out.println(format("Wrote to '%s' ..., took %s ms.", outFile, tookMs));
}
}

protected static void fileInStdOut(final String inFileName) {
final File inFile = new File(inFileName);

final long startMs = System.currentTimeMillis();
boolean success = false;
try (InputStream is = new FileInputStream(inFile);
OutputStream os = System.out) {
LOG.log(Level.FINE, format("Reading from '%s' ...", inFile));
SortXmlEngine engine = new SortXmlEngine();
engine.sort(is, os);
success = true;
} catch (FileNotFoundException e) {
logException(e);
} catch (IOException e) {
logException(e);
}
if (success) {
final long endMs = System.currentTimeMillis();
final long tookMs = endMs - startMs;
LOG.log(Level.FINE, format("Wrote to 'stdout' ..., took %s ms.", tookMs));
}
}

protected static void stdInStdOut() {

final long startMs = System.currentTimeMillis();
boolean success = false;
try (InputStream is = System.in;
OutputStream os = System.out) {
LOG.log(Level.FINE, "Reading from 'stdin' ...");
SortXmlEngine engine = new SortXmlEngine();
engine.sort(is, os);
success = true;
} catch (FileNotFoundException e) {
logException(e);
} catch (IOException e) {
logException(e);
}
if (success) {
final long endMs = System.currentTimeMillis();
final long tookMs = endMs - startMs;
LOG.log(Level.FINE, format("Wrote to 'stdout' ..., took %s ms.", tookMs));
}
}

protected static void help() {
System.out.println("Usage: [inputFile] [outputFile]");
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/ltpeacock/sorter/package-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* Package containing subpackages for sorting various file types.
* @author LieutenantPeacock
*/
package com.ltpeacock.sorter;
58 changes: 58 additions & 0 deletions src/main/java/com/ltpeacock/sorter/xml/ElementComparator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.ltpeacock.sorter.xml;

import java.util.Comparator;

import org.w3c.dom.Element;

/**
*
* @author LieutenantPeacock
*
*/
public class ElementComparator implements Comparator<Element> {

private static final String NAME = "name";

public ElementComparator() {
}

@Override
public int compare(final Element arg0, final Element arg1) {
int c = Util.compare(safeToUpper(
reverseColumns(arg0.getNodeName())),
safeToUpper(reverseColumns(arg1.getNodeName())));
if (0 == c) {
final String nameAttr0 = arg0.getAttribute(NAME);
final String nameAttr1 = arg1.getAttribute(NAME);
c = Util.compare(safeToUpper(nameAttr0), safeToUpper(nameAttr1));
}
return c;
}

protected String reverseColumns(final String input) {
final String result;
if (input == null) {
result = input;
} else {
final int idx = input.indexOf(':');
if (idx > 0) {
final String s1 = input.substring(0, idx);
final String s2 = input.substring(idx + 1);
result = s2 + ':' + s1;
} else {
result = input;
}
}
return result;
}

protected String safeToUpper(final String input) {
final String result;
if (input == null) {
result = null;
} else {
result = input.toUpperCase();
}
return result;
}
}
144 changes: 144 additions & 0 deletions src/main/java/com/ltpeacock/sorter/xml/SortXmlEngine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package com.ltpeacock.sorter.xml;

import static java.lang.String.format;
import static com.ltpeacock.sorter.xml.Util.logException;
import static com.ltpeacock.sorter.xml.Util.removeEmptyLines;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class SortXmlEngine {
private static final Logger LOG = Logger.getLogger(SortXmlEngine.class.getName());

public void sort(final InputStream in, final OutputStream os) {
try (BufferedInputStream bis = new BufferedInputStream(in);
BufferedOutputStream bos = new BufferedOutputStream(os);
PrintWriter pw = new PrintWriter(bos)) {
final Document doc = readXml(in);
final Element rootDocElement = doc.getDocumentElement();
sortElement(rootDocElement);
final String prettyXml = XmlPrettyPrint.prettyXml(doc);
final String prettyXml2 = XmlPrettyPrint.prettyFormat(prettyXml);
final String prettyXml4 = removeEmptyLines(prettyXml2);
final String prettyXml5 = prettyXml4.replaceAll("\">", "\" >").replaceAll("\"/>", "\" />");
final String prettyXml6 = removeExtraWsdlpartClose(prettyXml5);
pw.print(prettyXml6);
} catch (IOException e) {
logException(e);
}
}

static String removeExtraWsdlpartClose(final String inputStr) {
final String s1 = removeExtraClose(inputStr, "wsdl:part");
final String s2 = removeExtraClose(s1, "wsdl:input");
final String s3 = removeExtraClose(s2, "wsdl:output");
final String s4 = removeExtraClose(s3, "xs:element");
final String s5 = s4.replaceFirst("\\?><wsdl:definitions", "\\?>\r\n<wsdl:definitions");
final String s6 = s5.replaceAll("\" >", "\">");
return s6;
}

static String removeExtraClose(final String inputStr, final String tag) {
final Pattern pattern = Pattern.compile("(<" + tag + " .+ )>\\r?\\n?[ \t]*</" + tag + ">", Pattern.MULTILINE);
final Matcher m = pattern.matcher(inputStr);
final String prettyXml3 = m.replaceAll("$1/>");

return prettyXml3;
}

/**
* @param rootDocElement
*/
void sortElement(final Element rootDocElement) {
final NodeList nodeList = rootDocElement.getChildNodes();
final int length = nodeList.getLength();
final List<Element> elemList0 = new ArrayList<>(length);
for (int i = 0; i < length; i++) {
Node currentNode = nodeList.item(i);

if (currentNode.getNodeType() == Node.ELEMENT_NODE) {

final String nodeName = currentNode.getNodeName();
LOG.fine(format("localName [%s]", nodeName));
elemList0.add((Element) currentNode);
if (currentNode.getChildNodes() != null && currentNode.getChildNodes().getLength() > 0) {
sortElement((Element) currentNode);
}
} else {
LOG.fine(format("Node type [%s]", currentNode.getNodeType()));
}
}
Collections.sort(elemList0, new ElementComparator());
int count = 0;
for (Node elem : elemList0) {
count++;
LOG.fine(format("removing Count [%s], name[%s]", count, elem.getNodeName()));
rootDocElement.removeChild(elem);
}
int count2 = 0;
for (Node elem : elemList0) {
count2++;
LOG.fine(format("Count [%s], name[%s]", count2, elem.getNodeName()));
rootDocElement.appendChild(elem);
}
}

public static void printDocument(final Document doc, final OutputStream out)
throws IOException, TransformerException {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

LOG.info("===== printing XML =====");
transformer.transform(new DOMSource(doc),
new StreamResult(new OutputStreamWriter(out, "UTF-8")));
}

protected Document readXml(final InputStream is) {
DocumentBuilderFactory docBuilderFac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = null;
Document doc = null;
try {
docBuilder = docBuilderFac.newDocumentBuilder();
doc = docBuilder.parse(is);
} catch (ParserConfigurationException e) {
logException(e);
} catch (SAXException e) {
logException(e);
} catch (IOException e) {
logException(e);
}
return doc;
}
}
51 changes: 51 additions & 0 deletions src/main/java/com/ltpeacock/sorter/xml/Util.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.ltpeacock.sorter.xml;

import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Util {
private static final Logger LOG = Logger.getLogger(Util.class.getName());

private Util() {
throw new IllegalStateException("No instances of Util allowed");
}

public static int compare(final String s1, final String s2) {
return compare(s1, s2, false);
}

public static int compare(final String s1, final String s2, final boolean nullGreater) {
final int result;
if (s1 == s2) {
result = 0;
} else if (s1 == null) {
result = nullGreater ? 1 : -1;
} else if (s2 == null) {
result = nullGreater ? -1 : 1;
} else {
result = s1.compareTo(s2);
}

return result;
}

/**
* @param inputStr
* @return
*/
public static String removeEmptyLines(final String inputStr) {
final Pattern pattern = Pattern.compile("(^[ \t]*$\\r\\n)+", Pattern.MULTILINE);
final Matcher m = pattern.matcher(inputStr);
m.replaceAll("\r\n");
final String prettyXml3 = m.replaceAll("\r\n");
final String prettyXml4 = prettyXml3.replaceAll("(\\r\\n)+", "\r\n");
return prettyXml4;
}

public static void logException(final Exception e) {
LOG.log(Level.SEVERE, "Error", e);
throw new RuntimeException(e);
}
}
Loading

0 comments on commit 0b46abe

Please sign in to comment.