package org.simpleframework.xml.util;
import java.io.ByteArrayOutputStream;
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.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;
public class Formatter {
private static final String LS_FEATURE_KEY = "LS";
private static final String LS_FEATURE_VERSION = "3.0";
private static final String CORE_FEATURE_KEY = "Core";
private static final String CORE_FEATURE_VERSION = "2.0";
private final boolean preserveComments;
public Formatter() {
this(false);
}
public Formatter(boolean preserveComments) {
this.preserveComments = preserveComments;
}
public String format(String source) {
StringWriter writer = new StringWriter();
format(source, writer);
return writer.toString();
}
public void format(String source, Writer writer) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
DocumentBuilder builder = factory.newDocumentBuilder();
Reader reader = new StringReader(source);
InputSource input = new InputSource(reader);
Document document = builder.parse(input);
format(document, writer);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void format(Document document, Writer writer) {
DOMImplementation implementation = document.getImplementation();
if(implementation.hasFeature(LS_FEATURE_KEY, LS_FEATURE_VERSION) && implementation.hasFeature(CORE_FEATURE_KEY, CORE_FEATURE_VERSION)) {
DOMImplementationLS implementationLS = (DOMImplementationLS) implementation.getFeature(LS_FEATURE_KEY, LS_FEATURE_VERSION);
LSSerializer serializer = implementationLS.createLSSerializer();
DOMConfiguration configuration = serializer.getDomConfig();
configuration.setParameter("format-pretty-print", Boolean.TRUE);
configuration.setParameter("comments", preserveComments);
LSOutput output = implementationLS.createLSOutput();
output.setEncoding("UTF-8");
output.setCharacterStream(writer);
serializer.write(document, output);
}
}
private String read(File file) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
InputStream source = new FileInputStream(file);
byte[] chunk = new byte[1024];
int count = 0;
while((count = source.read(chunk)) != -1) {
buffer.write(chunk, 0, count);
}
return buffer.toString("UTF-8");
}
/**
* Scripts to execute the XML formatter.
*
* #!/bin/bash
* xml.bat $1 $2 $3
*
* echo off
* java -jar c:/start/bin/xml.jar %1 %2 %3 %4
*
* @param list arguments to the formatter
*/
public static void main(String list[]) throws Exception {
List<String> values = new ArrayList<String>();
for(String argument : list) {
if(argument != null && argument.trim().length() > 0) {
values.add(argument.trim());
}
}
if(values.size() == 0) {
throw new FileNotFoundException("File needs to be specified as an argument");
}
Formatter formatter = new Formatter();
File file = new File(values.get(0));
String source = formatter.read(file); // read before opening for write
if(values.size() == 1) {
formatter.format(source, new OutputStreamWriter(System.out));
}
else if(values.size() == 2) {
formatter.format(source, new OutputStreamWriter(new FileOutputStream(new File(values.get(1)))));
}
else {
StringBuilder builder = new StringBuilder();
for(String value : values) {
builder.append("'").append(value).append("'");
}
throw new IllegalArgumentException("At most two arguments can be specified, you specified "+builder);
}
}
}