package se.unlogic.standardutils.xml;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URI;
import java.util.Collection;
import java.util.Map.Entry;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
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 XMLUtils {
private static DocumentBuilder documentBuilder;
private static DocumentBuilder namespaceAwareDocumentBuilder;
static {
try {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilder = documentBuilderFactory.newDocumentBuilder();
documentBuilderFactory.setNamespaceAware(true);
namespaceAwareDocumentBuilder = documentBuilderFactory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
public static Document createDomDocument() {
return documentBuilder.newDocument();
}
public static Document createNamespaceAwareDomDocument() {
return namespaceAwareDocumentBuilder.newDocument();
}
public static String toString(Document doc, String encoding, boolean indent) throws TransformerFactoryConfigurationError, TransformerException {
Source source = new DOMSource(doc);
StringWriter sw = new StringWriter();
Result result = new StreamResult(sw);
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.setOutputProperty(OutputKeys.ENCODING, encoding);
if (indent) {
xformer.setOutputProperty(OutputKeys.INDENT, "yes");
}
xformer.transform(source, result);
return sw.getBuffer().toString();
}
public static void toString(Document doc, String encoding, Writer w, boolean indent) throws TransformerFactoryConfigurationError, TransformerException {
Source source = new DOMSource(doc);
Result result = new StreamResult(w);
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.setOutputProperty(OutputKeys.ENCODING, encoding);
if (indent) {
xformer.setOutputProperty(OutputKeys.INDENT, "yes");
}
xformer.transform(source, result);
}
public static Document parseXmlFile(String filename, boolean validating, boolean namespaceAware) throws SAXException, IOException, ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(namespaceAware);
factory.setValidating(validating);
Document doc = factory.newDocumentBuilder().parse(new File(filename));
return doc;
}
public static Document parseXmlFile(URI uri, boolean validating) throws SAXException, IOException, ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(validating);
Document doc = factory.newDocumentBuilder().parse(uri.toString());
return doc;
}
public static Document parseXmlFile(File f, boolean validating) throws SAXException, IOException, ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(validating);
Document doc = factory.newDocumentBuilder().parse(f);
return doc;
}
public static Document parseXmlFile(InputStream stream, boolean validating) throws SAXException, IOException, ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(validating);
Document doc = factory.newDocumentBuilder().parse(stream);
return doc;
}
public static Element createElement(String name, Object value, Document doc) {
Element element = doc.createElement(name);
element.appendChild(doc.createTextNode(value.toString()));
return element;
}
public static Element createCDATAElement(String name, Object value, Document doc) {
Element element = doc.createElement(name);
element.appendChild(doc.createCDATASection(value.toString()));
return element;
}
public static void writeXmlFile(Document doc, File file, boolean indent) throws TransformerFactoryConfigurationError, TransformerException {
// Prepare the DOM document for writing
Source source = new DOMSource(doc);
// Prepare the output file
Result result = new StreamResult(file);
// Write the DOM document to the file
Transformer xformer = TransformerFactory.newInstance().newTransformer();
if (indent) {
xformer.setOutputProperty(OutputKeys.INDENT, "yes");
}
xformer.transform(source, result);
}
public static void writeXmlFile(Document doc, File file, Entry<String,String>... outputKeys) throws TransformerFactoryConfigurationError, TransformerException {
// Prepare the DOM document for writing
Source source = new DOMSource(doc);
// Prepare the output file
Result result = new StreamResult(file);
// Write the DOM document to the file
Transformer xformer = TransformerFactory.newInstance().newTransformer();
if(outputKeys != null){
for(Entry<String,String> entry : outputKeys){
xformer.setOutputProperty(entry.getKey(), entry.getValue());
}
}
xformer.transform(source, result);
}
public static void writeXmlFile(Document doc, String filename, boolean indent) throws TransformerFactoryConfigurationError, TransformerException {
// Prepare the output file
File file = new File(filename);
writeXmlFile(doc, file, indent);
}
public static void append(Document doc, Element targetElement, Collection<? extends XMLable> beans) {
if (beans != null && !beans.isEmpty()) {
for (XMLable xmlable : beans) {
targetElement.appendChild(xmlable.toXML(doc));
}
}
}
public static void append(Document doc, Element targetElement, String elementName, Collection<? extends XMLable> beans) {
if (beans != null && !beans.isEmpty()) {
Element subElement = doc.createElement(elementName);
targetElement.appendChild(subElement);
for (XMLable xmlable : beans) {
subElement.appendChild(xmlable.toXML(doc));
}
}
}
public static void appendNewCDATAElement(Document doc, Element targetElement, String elementName, String value) {
if(value != null){
targetElement.appendChild(createCDATAElement(elementName, value, doc));
}
}
public static void appendNewElement(Document doc, Element targetElement, String elementName, String value) {
if(value != null){
targetElement.appendChild(createElement(elementName, value, doc));
}
}
public static void appendNewCDATAElement(Document doc, Element targetElement, String elementName, Object value) {
if(value != null){
appendNewCDATAElement(doc,targetElement,elementName,value.toString());
}
}
public static void appendNewElement(Document doc, Element targetElement, String elementName, Object value) {
if(value != null){
appendNewElement(doc,targetElement,elementName,value.toString());
}
}
/**
* Adds or replaces node in parent.
* @param parent
* @param node
* @throws Exception - Node cannot exist more than once,
* i.e. multiple nodes with the same name cannot exist in parent.
*/
public static void replaceSingleNode(Element parent, final Node node) throws RuntimeException {
NodeList nodes = parent.getElementsByTagName(node.getNodeName());
if(nodes.getLength() > 1) {
throw new RuntimeException("Parent element contains multiple nodes with the name " + node.getNodeName());
}
if(nodes.getLength() == 0) {
parent.appendChild(node);
} else {
parent.replaceChild(node, nodes.item(0));
}
}
}