com.crabshue.commons.xml.XmlPrintUtils Maven / Gradle / Ivy
package com.crabshue.commons.xml;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import com.crabshue.commons.exceptions.SystemException;
import com.crabshue.commons.xml.exceptions.XmlErrorType;
import com.crabshue.commons.xml.inputsource.InputSourceBuilder;
import com.crabshue.commons.xml.processinginstructions.ProcessingInstructionsConstants;
import lombok.Data;
import lombok.NonNull;
/**
* Utility class for printing XML documents.
*
*/
public class XmlPrintUtils {
/**
* Converts a DOM document, into a set of string lines, preserving or not the XML declaration processing instruction.
*
* @param doc the source document to convert
* @return the string collection representation of a document.
*/
public static Collection stringify(@NonNull final Document doc) {
return stringify(doc, Options.defaultOptions());
}
/**
* Converts a DOM document, into a set of string lines, preserving or not the XML declaration processing instruction.
*
* @param doc the source document to convert
* @param options
* @return the string collection representation of a document.
*/
public static Collection stringify(@NonNull final Document doc,
@NonNull final XmlPrintUtils.Options options) {
StringWriter sw = new StringWriter();
try {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, options.isOmitXmlDeclaration() ? "yes" : "no");
transformer.setOutputProperty(OutputKeys.METHOD, options.getOutputMethod());
transformer.setOutputProperty(OutputKeys.INDENT, options.isIndent() ? "yes" : "no");
transformer.setOutputProperty(OutputKeys.ENCODING, options.getEncoding());
transformer.transform(new DOMSource(doc), new StreamResult(sw));
} catch (Exception ex) {
throw new SystemException(XmlErrorType.ERROR_MODIFYING_XML, "Error converting to String", ex);
}
Collection lines = Arrays.asList(StringUtils.split(sw.toString(), "\n"));
return XmlPrintUtils.isolateProcessingInstructions(lines);
}
/**
* Prettify a collection of {@link String lines} (representing an XML).
*
* @param lines the collection of lines.
* @return the prettified lines.
*/
public static Collection prettyPrint(@NonNull final Collection lines) {
Collection ret;
final Document document = XmlDocumentBuilder.of(InputSourceBuilder.newInputSource(lines)).build();
ret = XmlPrintUtils.stringify(document, new Options().setOmitXmlDeclaration(false));
ret = isolateProcessingInstructions(ret);
return ret;
}
/**
* Modify a set of {@link String lines}, to put the xml processing instructions on individual lines.
*
* @param lines the lines.
* @return the prettified lines.
*/
public static Collection isolateProcessingInstructions(@NonNull final Collection lines) {
Collection ret = new ArrayList<>();
Pattern pattern = Pattern.compile(ProcessingInstructionsConstants.PROCESSING_INSTRUCTION_REGEXP);
for (String line : lines) {
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
String s = line.replaceAll(ProcessingInstructionsConstants.PROCESSING_INSTRUCTION_REGEXP, "\n$0\n");
ret.addAll(Arrays.asList(StringUtils.split(s, "\n")));
} else {
ret.add(line);
}
}
return ret;
}
/**
* Stringify options
*/
@Data
public static class Options {
private boolean omitXmlDeclaration = false;
private String outputMethod = "xml";
private String encoding = "UTF-8";
private boolean indent = true;
public static Options defaultOptions() {
return new Options();
}
}
}