package me.pbox.xml;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.namespace.QName;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.*;
import java.io.*;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Maxim Shipko (sladethe@gmail.com)
* Date: 14.09.11
*/
@SuppressWarnings("UnusedDeclaration")
public final class XmlUtil {
private static final Lock factoryLock = new ReentrantLock();
private static final Lock expressionLock = new ReentrantLock();
private XmlUtil() {
throw new UnsupportedOperationException();
}
/**
* Parses XML string and extracts value.
*
* @param xmlFile XML to be scanned.
* @param xPath XPath expression.
* @param clazz {@link Boolean}, {@link String}, {@link Integer}, {@link Double},
* {@link org.w3c.dom.NodeList} and {@link org.w3c.dom.Node} classes are supported now.
* @param <T> Return type.
* @return Return value.
* @throws java.io.IOException In case of I/O error.
*/
public static <T> T extractFromXml(/*@Nonnull*/ final File xmlFile, final String xPath, final Class<T> clazz)
throws IOException {
return internalExtractFromXml(new FileInputStream(xmlFile), xPath, clazz);
}
/**
* Parses XML string and extracts value.
*
* @param xmlInputStream XML to be scanned.
* @param xPath XPath expression.
* @param clazz {@link Boolean}, {@link String}, {@link Integer}, {@link Double},
* {@link org.w3c.dom.NodeList} and {@link org.w3c.dom.Node} classes are supported now.
* @param <T> Return type.
* @return Return value.
* @throws java.io.IOException In case of I/O error.
*/
public static <T> T extractFromXml(final InputStream xmlInputStream, final String xPath, final Class<T> clazz)
throws IOException {
return internalExtractFromXml(xmlInputStream, xPath, clazz);
}
/**
* Writes XML document into file.
*
* @param xmlFile File to write.
* @param document XML document.
* @throws java.io.IOException In case of I/O error.
*/
public static void writeXml(/*@Nonnull*/ final File xmlFile, /*@Nonnull*/ final Document document) throws IOException {
internalWriteXml(new FileOutputStream(xmlFile), document);
}
/**
* Writes XML document into file.
*
* @param xmlOutputStream Stream to write.
* @param document XML document.
* @throws java.io.IOException In case of I/O error.
*/
public static void writeXml(final OutputStream xmlOutputStream, /*@Nonnull*/ final Document document) throws IOException {
internalWriteXml(xmlOutputStream, document);
}
/**
* Changes the value describing by XPath to specific value and updates file.
*
* @param xmlFile Which will read first and updated later.
* @param xPath XPath to find specific Node.
* @param value Value to be set for found node.
* @throws java.io.IOException In case of I/O error.
*/
public static void updateXml(/*@Nonnull*/ final File xmlFile, final String xPath, final String value) throws IOException {
try {
ByteArrayOutputStream xmlOutputStream = new ByteArrayOutputStream();
internalUpdateXml(
new ByteArrayInputStream(FileUtils.readFileToByteArray(xmlFile)),
xmlOutputStream, xPath, value
);
FileUtils.writeByteArrayToFile(xmlFile, xmlOutputStream.toByteArray());
} catch (IOException e) {
throw new IOException(
"Can't find, read or update file '" + xmlFile.getName()
+ "' while evaluating XPath '" + xPath + "'.", e
);
}
}
/**
* Changes the value describing by XPath to specific value and writes modified XML document into output stream.
*
* @param xmlInputStream Stream to read.
* @param xmlOutputStream Stream to write.
* @param xPath XPath to find specific Node.
* @param value Value to be set for found node.
* @throws java.io.IOException In case of I/O error.
*/
public static void updateXml(
final InputStream xmlInputStream, final OutputStream xmlOutputStream, final String xPath, final String value)
throws IOException {
internalUpdateXml(xmlInputStream, xmlOutputStream, xPath, value);
}
/**
* Changes the inner text of an XML-element described by XPath to specific value and updates file.
*
* @param xmlFile Which will read first and updated later.
* @param xPath XPath to find specific {@code {@link org.w3c.dom.Element }}.
* @param value New text value.
* @throws java.io.IOException In case of I/O error.
*/
public static void updateText(/*@Nonnull*/ final File xmlFile, final String xPath, /*@Nullable*/ final String value)
throws IOException {
try {
ByteArrayOutputStream xmlOutputStream = new ByteArrayOutputStream();
internalUpdateText(
new ByteArrayInputStream(FileUtils.readFileToByteArray(xmlFile)),
xmlOutputStream, xPath, value
);
FileUtils.writeByteArrayToFile(xmlFile, xmlOutputStream.toByteArray());
} catch (IOException e) {
throw new IOException(
"Can't find, read or update file '" + xmlFile.getName()
+ "' while evaluating XPath '" + xPath + "'.", e
);
}
}
/**
* Changes the inner text of an XML-element described by XPath to specific value
* and writes modified XML document into output stream.
*
* @param xmlInputStream Stream to read.
* @param xmlOutputStream Stream to write.
* @param xPath XPath to find specific {@code {@link org.w3c.dom.Element }}.
* @param value New text value.
* @throws java.io.IOException In case of I/O error.
*/
public static void updateText(
final InputStream xmlInputStream, final OutputStream xmlOutputStream, final String xPath,
/*@Nullable*/ final String value) throws IOException {
internalUpdateText(xmlInputStream, xmlOutputStream, xPath, value);
}
/**
* Ensures that XML-element with {@code newAttributes} does exist and creates it if not.
* <p/>
* Method uses {@code filterAttributes} to uniquely identify an XML-element.
* If such element does exist, all its attributes will be overriden with values of {@code newAttributes},
* else a new element will be created.
*
* @param xmlFile Which will read first and updated later.
* @param parentElementXPath XPath to find element that should contain specified element.
* @param elementName Name of the element to create.
* @param filterAttributes Collection of attributes which allows to uniquely identify an XML-element.
* @param newAttributes Collection of attributes which an XML-element should have
* or {@code null} if {@code filterAttributes} should be considered
* also as {@code newAttributes}.
* @param obsoleteAttributes Collection of attribute names which should be removed from the element
* or {@code null} if no such action is required.
* @throws java.io.IOException In case of I/O error.
*/
public static void ensureXmlElementExists(
/*@Nonnull*/ final File xmlFile, /*@Nonnull*/ final String parentElementXPath, /*@Nonnull*/ final String elementName,
/*@Nonnull*/ final Map<String, String> filterAttributes, /*@Nullable*/ final Map<String, String> newAttributes,
/*@Nullable*/ final Set<String> obsoleteAttributes) throws IOException {
try {
ByteArrayOutputStream xmlOutputStream = new ByteArrayOutputStream();
internalEnsureXmlElementExists(
new ByteArrayInputStream(FileUtils.readFileToByteArray(xmlFile)),
xmlOutputStream,
parentElementXPath, elementName,
filterAttributes, newAttributes, obsoleteAttributes
);
FileUtils.writeByteArrayToFile(xmlFile, xmlOutputStream.toByteArray());
} catch (IOException e) {
throw new IOException(
"Can't find, read or update file '" + xmlFile.getName()
+ "' while evaluating XPath '" + parentElementXPath + "'.", e
);
}
}
/**
* Ensures that XML-element with {@code newAttributes} does exist and creates it if not.
* <p/>
* Method uses {@code filterAttributes} to uniquely identify an XML-element.
* If such element does exist, all its attributes will be overriden with values of {@code newAttributes},
* else a new element will be created.
*
* @param xmlInputStream Stream to read.
* @param xmlOutputStream Stream to write.
* @param parentElementXPath XPath to find element that should contain specified element.
* @param elementName Name of the element to create.
* @param filterAttributes Collection of attributes which allows to uniquely identify an XML-element.
* @param newAttributes Collection of attributes which an XML-element should have
* or {@code null} if {@code filterAttributes} should be considered
* also as {@code newAttributes}.
* @param obsoleteAttributes Collection of attribute names which should be removed from the element
* or {@code null} if no such action is required.
* @throws java.io.IOException In case of I/O error.
*/
public static void ensureXmlElementExists(
/*@Nonnull*/ final InputStream xmlInputStream, /*@Nonnull*/ final OutputStream xmlOutputStream,
/*@Nonnull*/ final String parentElementXPath, /*@Nonnull*/ final String elementName,
/*@Nonnull*/ final Map<String, String> filterAttributes, /*@Nullable*/ final Map<String, String> newAttributes,
/*@Nullable*/ final Set<String> obsoleteAttributes) throws IOException {
internalEnsureXmlElementExists(
xmlInputStream, xmlOutputStream,
parentElementXPath, elementName,
filterAttributes, newAttributes, obsoleteAttributes
);
}
/**
* Removes all elements Xml by XPath.
*
* @param xmlFile From which will be removed elements.
* @param elementXPath XPath of elements to remove.
* @throws java.io.IOException In case of I/O error.
*/
public static void removeElementsIfExists(/*@Nonnull*/ File xmlFile, /*@Nonnull*/ String elementXPath)
throws IOException {
try {
ByteArrayOutputStream xmlOutputStream = new ByteArrayOutputStream();
removeElementsIfExists(new ByteArrayInputStream(FileUtils.readFileToByteArray(xmlFile)), xmlOutputStream, elementXPath);
FileUtils.writeByteArrayToFile(xmlFile, xmlOutputStream.toByteArray());
} catch (IOException e) {
throw new IOException(
"Can't find, read or update file '" + xmlFile.getName()
+ "' while evaluating XPath '" + elementXPath + "'.", e
);
}
}
/**
* Removes all elements from Xml by XPath.
*
* @param xmlInputStream Stream to read.
* @param xmlOutputStream Stream to write.
* @param elementXPath XPath of elements to remove. @throws IOException In case of I/O error.
*/
public static void removeElementsIfExists(
/*@Nonnull*/ InputStream xmlInputStream, /*@Nonnull*/ OutputStream xmlOutputStream,
/*@Nonnull*/ String elementXPath) throws IOException {
internalRemoveElementsIfExists(xmlInputStream, xmlOutputStream, elementXPath);
}
/*@Nullable*/
public static String formatEnumValueForXml(/*@Nullable*/ Enum enumValue) {
return enumValue == null ? null : enumValue.name().toLowerCase().replace('_', '-');
}
/*@Nullable*/
public static <T extends Enum<T>> T extractEnumValueFromXml(/*@Nonnull*/ String enumFormat, Class<T> enumClass) {
return StringUtils.isBlank(enumFormat)
? null
: Enum.valueOf(enumClass, enumFormat.toUpperCase().replace('-', '_'));
}
/*@Nonnull*/
@SuppressWarnings("unchecked")
private static <T> T internalExtractFromXml(InputStream xmlInputStream, String xPath, Class<T> clazz)
throws IOException {
byte[] xmlBytes = IOUtils.toByteArray(xmlInputStream);
IOUtils.closeQuietly(xmlInputStream);
InputStream xmlBytesInputStream = new ByteArrayInputStream(xmlBytes);
XPath xp = newXPathFactory().newXPath();
QName type;
if (clazz == Boolean.class) {
type = XPathConstants.BOOLEAN;
} else if (clazz == String.class) {
type = XPathConstants.STRING;
} else if (clazz == Integer.class || clazz == Double.class) {
type = XPathConstants.NUMBER;
} else if (clazz == NodeList.class) {
type = XPathConstants.NODESET;
} else if (clazz == Node.class) {
type = XPathConstants.NODE;
} else {
throw new IllegalArgumentException("Illegal argument 'clazz': '" + clazz + "'.");
}
try {
XPathExpression expression = xp.compile(xPath);
Object result = evaluateXPath(xmlBytesInputStream, expression, type);
if (XPathConstants.NUMBER.equals(type) && clazz == Integer.class) {
result = ((Double) result).intValue();
}
return (T) result;
} catch (XPathException e) {
String xmlString = new String(xmlBytes, "UTF-8");
throw new IOException("Can't get xpath \"" + xPath + "\" from \""
+ StringUtils.abbreviate(xmlString, 128) + "\".", e);
} finally {
IOUtils.closeQuietly(xmlBytesInputStream);
}
}
private static void internalWriteXml(OutputStream xmlOutputStream, /*@Nonnull*/ Document document) throws IOException {
formatDocument(document);
Source source = new DOMSource(document);
try {
Transformer transformer = newTransformerFactory().newTransformer();
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
StreamResult result = new StreamResult(xmlOutputStream);
transformer.transform(source, result);
} catch (TransformerConfigurationException e) {
throw new IOException("Transformer configuration is illegal.", e);
} catch (TransformerException e) {
throw new IOException("Transformer failed.", e);
} finally {
IOUtils.closeQuietly(xmlOutputStream);
}
}
private static void internalUpdateXml(
InputStream xmlInputStream, OutputStream xmlOutputStream, String xPath, String value) throws IOException {
XPath xp = newXPathFactory().newXPath();
try {
XPathExpression root = xp.compile("/");
Document document = (Document) evaluateXPath(xmlInputStream, root, XPathConstants.NODE);
XPathExpression nodeXPath = xp.compile(xPath);
Node node = (Node) evaluateXPath(document, nodeXPath, XPathConstants.NODE);
node.setNodeValue(value);
internalWriteXml(xmlOutputStream, document);
} catch (XPathExpressionException e) {
throw new IOException("Illegal XPath.", e);
} finally {
IOUtils.closeQuietly(xmlInputStream);
IOUtils.closeQuietly(xmlOutputStream);
}
}
private static void internalUpdateText(
InputStream xmlInputStream, OutputStream xmlOutputStream, String xPath, /*@Nullable*/ String value)
throws IOException {
XPath xp = newXPathFactory().newXPath();
try {
Document document = (Document) evaluateXPath(xmlInputStream, xp.compile("/"), XPathConstants.NODE);
NodeList nodes = (NodeList) evaluateXPath(document, xp.compile(xPath), XPathConstants.NODESET);
for (int nodeIndex = nodes.getLength() - 1; nodeIndex >= 0; --nodeIndex) {
Node node = nodes.item(nodeIndex);
if (!(node instanceof Element)) {
throw new IOException("Node specified by XPath '" + xPath + "' is not an XML-element.");
}
Element element = (Element) node;
if (!hasOnlyTextChildren(element)) {
throw new IOException(String.format(
"Element specified by XPath '%s' has at least one child which isn't plain text node.",
xPath
));
}
Node childNode = element.getFirstChild();
if (value == null) {
while (childNode != null) {
element.removeChild(childNode);
childNode = element.getFirstChild();
}
} else {
if (childNode == null) {
element.appendChild(element.getOwnerDocument().createTextNode(value));
} else {
((Text) childNode).replaceWholeText(value);
}
}
}
internalWriteXml(xmlOutputStream, document);
} catch (XPathExpressionException e) {
throw new IOException("Illegal XPath.", e);
} finally {
IOUtils.closeQuietly(xmlInputStream);
IOUtils.closeQuietly(xmlOutputStream);
}
}
/**
* Ensures that XML-element with {@code newAttributes} does exist and creates it if not.
* <p/>
* Method uses {@code filterAttributes} to uniquely identify an XML-element.
* If such element does exist, all its attributes will be overriden with values of {@code newAttributes},
* else a new element will be created.
*
* @param xmlInputStream Stream to read.
* @param xmlOutputStream Stream to write.
* @param parentElementXPath XPath to find element that should contain specified element.
* @param elementName Name of the element to create.
* @param filterAttributes Collection of attributes which allows to uniquely identify an XML-element.
* @param newAttributes Collection of attributes which an XML-element should have
* or {@code null} if {@code filterAttributes} should be considered
* also as {@code newAttributes}.
* @param obsoleteAttributes Collection of attribute names which should be removed from the element
* or {@code null} if no such action is required.
* @throws java.io.IOException In case of I/O error.
*/
@SuppressWarnings({"OverlyLongMethod", "OverlyComplexMethod"})
private static void internalEnsureXmlElementExists(
/*@Nonnull*/ InputStream xmlInputStream, /*@Nonnull*/ OutputStream xmlOutputStream,
/*@Nonnull*/ String parentElementXPath, /*@Nonnull*/ String elementName,
/*@Nonnull*/ Map<String, String> filterAttributes, /*@Nullable*/ Map<String, String> newAttributes,
/*@Nullable*/ Set<String> obsoleteAttributes) throws IOException {
XPath xp = newXPathFactory().newXPath();
try {
// Load DOM-document, compile and execute XPath expression.
XPathExpression root = xp.compile("/");
Document document = (Document) evaluateXPath(xmlInputStream, root, XPathConstants.NODE);
XPathExpression parentNodeXPath = xp.compile(parentElementXPath);
Node parentNode = (Node) evaluateXPath(document, parentNodeXPath, XPathConstants.NODE);
NodeList childNodes = parentNode.getChildNodes();
Element element = null;
// Search for element with specified characteristics.
for (int childIndex = 0, childCount = childNodes.getLength(); childIndex < childCount; ++childIndex) {
Node childNode = childNodes.item(childIndex);
if (!elementName.equals(childNode.getNodeName())) {
continue;
}
NamedNodeMap actualAttributes = childNode.getAttributes();
if (actualAttributes == null) {
continue;
}
boolean matches = true;
for (Map.Entry<String, String> filterAttribute : filterAttributes.entrySet()) {
Node actualAttribute = actualAttributes.getNamedItem(filterAttribute.getKey());
if (actualAttribute == null || !filterAttribute.getValue().equals(actualAttribute.getNodeValue())) {
matches = false;
break;
}
}
if (matches) {
element = (Element) childNode;
break;
}
}
// Create new element if not found.
if (element == null) {
element = document.createElement(elementName);
parentNode.appendChild(element);
}
// Create or update attributes.
newAttributes = newAttributes == null ? filterAttributes : newAttributes;
for (Map.Entry<String, String> newAttribute : newAttributes.entrySet()) {
element.setAttribute(newAttribute.getKey(), newAttribute.getValue());
}
// Remove obsolete attributes.
if (obsoleteAttributes != null) {
for (String obsoleteAttribute : obsoleteAttributes) {
element.removeAttribute(obsoleteAttribute);
}
}
// Save DOM-document.
internalWriteXml(xmlOutputStream, document);
} catch (XPathExpressionException e) {
throw new IOException("Illegal XPath.", e);
} finally {
IOUtils.closeQuietly(xmlInputStream);
IOUtils.closeQuietly(xmlOutputStream);
}
}
/**
* Removes all elements from Xml by XPath.
*
* @param xmlInputStream Stream to read.
* @param xmlOutputStream Stream to write.
* @param elementXPath XPath of elements to remove. @throws IOException In case of I/O error.
*/
private static void internalRemoveElementsIfExists(
/*@Nonnull*/ InputStream xmlInputStream, /*@Nonnull*/ OutputStream xmlOutputStream,
/*@Nonnull*/ String elementXPath) throws IOException {
XPath xp = newXPathFactory().newXPath();
try {
XPathExpression root = xp.compile("/");
Document document = (Document) evaluateXPath(xmlInputStream, root, XPathConstants.NODE);
XPathExpression parentNodeXPath = xp.compile(elementXPath);
NodeList nodeList = (NodeList) evaluateXPath(document, parentNodeXPath, XPathConstants.NODESET);
for (int nodeIndex = 0; nodeIndex < nodeList.getLength(); nodeIndex++) {
Node node = nodeList.item(nodeIndex);
node.getParentNode().removeChild(node);
}
internalWriteXml(xmlOutputStream, document);
} catch (XPathExpressionException e) {
throw new IOException("Illegal XPath.", e);
} finally {
IOUtils.closeQuietly(xmlInputStream);
IOUtils.closeQuietly(xmlOutputStream);
}
}
@SuppressWarnings({"HardcodedLineSeparator"})
private static void formatDocument(/*@Nonnull*/ Document document) {
formatElement(document, document.getDocumentElement(), 1);
formatElementEnd(document, document.getDocumentElement(), "\n");
}
@SuppressWarnings({"ChainOfInstanceofChecks", "HardcodedLineSeparator", "OverlyComplexMethod"})
private static void formatElement(/*@Nonnull*/ Document document, /*@Nonnull*/ Element element, int depth) {
String formatString = '\n' + StringUtils.repeat(" ", depth);
Node node = element.getFirstChild();
while (node != null) {
if (node instanceof Element) {
formatElement(document, (Element) node, depth + 1);
formatElementStart(document, (Element) node, formatString);
formatElementEnd(document, (Element) node, formatString);
} else if (node instanceof Text) {
Text textNode = (Text) node;
String text = textNode.getWholeText();
if (hasOnlyTextSiblings(textNode)) {
String trimmedText = text.trim();
if (!trimmedText.equals(text)) {
textNode.replaceWholeText(trimmedText);
}
} else {
if (!text.trim().isEmpty()) {
textNode.replaceWholeText(formatString + trimLeft(text));
}
}
}
node = node.getNextSibling();
}
}
@SuppressWarnings({"ChainOfInstanceofChecks"})
private static void formatElementStart(
/*@Nonnull*/ Document document, /*@Nonnull*/ Element element, /*@Nonnull*/ String formatString) {
Node previousSibling = element.getPreviousSibling();
if (previousSibling == null || previousSibling instanceof Element) {
element.getParentNode().insertBefore(document.createTextNode(formatString), element);
} else if (previousSibling instanceof Text) {
Text textNode = (Text) previousSibling;
String text = textNode.getWholeText();
if (!formatString.equals(text)) {
textNode.replaceWholeText(trimRight(text) + formatString);
}
}
}
@SuppressWarnings({"ChainOfInstanceofChecks"})
private static void formatElementEnd(
/*@Nonnull*/ Document document, /*@Nonnull*/ Element element, /*@Nonnull*/ String formatString) {
Node lastChild = element.getLastChild();
if (lastChild != null) {
if (lastChild instanceof Element) {
element.appendChild(document.createTextNode(formatString));
} else if (lastChild instanceof Text) {
Text textNode = (Text) lastChild;
String text = textNode.getWholeText();
if (hasOnlyTextSiblings(textNode)) {
String trimmedText = text.trim();
if (!trimmedText.equals(text)) {
textNode.replaceWholeText(trimmedText);
}
} else {
if (!formatString.equals(text)) {
textNode.replaceWholeText(trimRight(text) + formatString);
}
}
}
}
}
/*@Nullable*/
private static String trimRight(/*@Nullable*/ String s) {
if (s == null) {
return null;
}
int lastIndex = s.length() - 1;
int index = lastIndex;
while (index >= 0 && s.charAt(index) <= ' ') {
--index;
}
return index == lastIndex ? s : s.substring(0, index + 1);
}
/*@Nullable*/
public static String trimLeft(/*@Nullable*/ String s) {
if (s == null) {
return null;
}
int lastIndex = s.length() - 1;
int index = 0;
while (index <= lastIndex && s.charAt(index) <= ' ') {
++index;
}
return index == 0 ? s : s.substring(index, lastIndex + 1);
}
public static boolean hasOnlyTextSiblings(/*@Nonnull*/ Node node) {
Node leftSibling = node.getPreviousSibling();
while (leftSibling != null) {
if (!(leftSibling instanceof Text)) {
return false;
}
leftSibling = leftSibling.getPreviousSibling();
}
Node rightSibling = node.getNextSibling();
while (rightSibling != null) {
if (!(rightSibling instanceof Text)) {
return false;
}
rightSibling = rightSibling.getNextSibling();
}
return true;
}
public static boolean hasOnlyTextChildren(/*@Nonnull*/ Node node) {
Node childNode = node.getFirstChild();
while (childNode != null) {
if (!(childNode instanceof Text)) {
return false;
}
childNode = childNode.getNextSibling();
}
return true;
}
/*@Nonnull*/
public static Document newDomDocument() throws IOException {
try {
DocumentBuilderFactory factory = newDocumentBuilderFactory();
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.newDocument();
} catch (ParserConfigurationException e) {
throw new IOException("Can't create new DOM-document.", e);
}
}
public static XPathFactory newXPathFactory() {
factoryLock.lock();
try {
return XPathFactory.newInstance();
} finally {
factoryLock.unlock();
}
}
public static TransformerFactory newTransformerFactory() {
factoryLock.lock();
try {
return TransformerFactory.newInstance();
} finally {
factoryLock.unlock();
}
}
public static DocumentBuilderFactory newDocumentBuilderFactory() {
factoryLock.lock();
try {
return DocumentBuilderFactory.newInstance();
} finally {
factoryLock.unlock();
}
}
public static Object evaluateXPath(InputStream xmlInputStream, /*@Nonnull*/ XPathExpression xPath, QName returnType)
throws XPathExpressionException {
expressionLock.lock();
try {
return xPath.evaluate(new InputSource(xmlInputStream), returnType);
} finally {
expressionLock.unlock();
}
}
public static Object evaluateXPath(Document document, /*@Nonnull*/ XPathExpression xPath, QName returnType)
throws XPathExpressionException {
expressionLock.lock();
try {
return xPath.evaluate(document, returnType);
} finally {
expressionLock.unlock();
}
}
public static Object evaluateXPath(Element element, /*@Nonnull*/ XPathExpression xPath, QName returnType)
throws XPathExpressionException {
expressionLock.lock();
try {
return xPath.evaluate(element, returnType);
} finally {
expressionLock.unlock();
}
}
public static Object evaluateXPath(InputStream xmlInputStream, /*@Nonnull*/ XPathExpression xPath)
throws XPathExpressionException {
expressionLock.lock();
try {
return xPath.evaluate(new InputSource(xmlInputStream));
} finally {
expressionLock.unlock();
}
}
public static Object evaluateXPath(Document document, /*@Nonnull*/ XPathExpression xPath)
throws XPathExpressionException {
expressionLock.lock();
try {
return xPath.evaluate(document);
} finally {
expressionLock.unlock();
}
}
public static Object evaluateXPath(Element element, /*@Nonnull*/ XPathExpression xPath)
throws XPathExpressionException {
expressionLock.lock();
try {
return xPath.evaluate(element);
} finally {
expressionLock.unlock();
}
}
public static void traverse(File xmlFile, DefaultHandler handler) {
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
try {
SAXParser saxParser = spf.newSAXParser();
saxParser.parse(xmlFile, handler);
} catch (ParserConfigurationException e) {
throw new RuntimeException("Can't configure XML-SAX parser.", e);
} catch (SAXException e) {
throw new RuntimeException("Can't run XML-SAX parser.", e);
} catch (IOException e) {
throw new RuntimeException("Invalid XML file '" + xmlFile + "'.", e);
}
}
public static void traverse(String xml, DefaultHandler handler) {
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
try {
SAXParser saxParser = spf.newSAXParser();
saxParser.parse(new InputSource(new StringReader(xml)), handler);
} catch (ParserConfigurationException e) {
throw new RuntimeException("Can't configure XML-SAX parser.", e);
} catch (SAXException e) {
throw new RuntimeException("Can't run XML-SAX parser.", e);
} catch (IOException e) {
throw new RuntimeException("Invalid XML '" + xml + "'.", e);
}
}
}