package com.ausregistry.jtoolkit2.xml;
import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* The purpose of an XMLDocument is to provide a simple xpath evaluation
* interface for extracting node values from an XML document. Where the names
* of elements are known in advance, non DOM-specific methods should be used in
* order to reduce the dependency of client classes on the DOM interface.
*/
public class XMLDocument {
private static XPathFactory xpathFactory;
private static NamespaceContext nsCtx;
private XPath xpath;
private final Element root;
private String sourceXMLString;
static {
xpathFactory = XPathFactory.newInstance();
nsCtx = new NamespaceContextImpl();
}
/**
* Create an XMLDocument rooted at the given element.
*
* @param root The root element of the XML document.
*/
public XMLDocument(Element root) {
this.root = root;
xpath = XMLDocument.newXPath();
xpath.setNamespaceContext(nsCtx);
}
XMLDocument(Element root, final String sourceXMLStringArg) {
this.root = root;
this.sourceXMLString = sourceXMLStringArg;
xpath = XMLDocument.newXPath();
xpath.setNamespaceContext(nsCtx);
}
private static XPath newXPath() {
return xpathFactory.newXPath();
}
/**
* Returns the XML used to produce the document.
*
* @return the XML
*/
public String getSourceXMLString() {
return sourceXMLString;
}
/**
* Use an XMLWriter to serialize to XML form the DOM tree associated with
* this XMLDocument.
*
* @return the string representation the document
*/
@Override
public String toString() {
XMLWriter writer = XMLWriter.newInstance();
writer.setRoot(root);
try {
return writer.toXML();
} catch (SAXException saxe) {
return "";
}
}
/**
* Get the number of nodes returned by the given xpath expression.
*
* @param query The XPath expression to evaluate.
* @return The number of nodes.
* @throws XPathExpressionException the XPath expression exception
*/
public int getNodeCount(String query) throws XPathExpressionException {
String result = xpath.evaluate(query, root);
return Integer.parseInt(result);
}
/**
* Get as a String the text content of a node identified by the given XPath
* expression.
*
* @param query The XPath expression to evaluate.
* @return The text content of the identified node.
* @throws XPathExpressionException the XPath expression exception
*/
public String getNodeValue(String query) throws XPathExpressionException {
return getNodeValue(query, root);
}
private String getNodeValue(String query, Node qRoot) throws XPathExpressionException {
String countStr = xpath.evaluate("count(" + query + ")", qRoot);
if (countStr.length() == 0 || Integer.valueOf(countStr) == 0) {
return null;
}
return xpath.evaluate(query, qRoot);
}
/**
* Get as a String the name of the node identified by the given XPath
* expression.
*
* @param query The XPath expression to evaluate.
* @return The name of the identified node.
* @throws XPathExpressionException the XPath expression exception
*/
public String getNodeName(String query) throws XPathExpressionException {
return getNodeName(query, root);
}
private String getNodeName(String query, Node qRoot) throws XPathExpressionException {
Node node = (Node) xpath.evaluate(query, qRoot, XPathConstants.NODE);
if (node != null) {
return node.getLocalName();
}
return null;
}
/**
* Get the names of all the nodes which are children of the node identified
* by the given XPath expression.
*
* @param query The XPath expression to evaluate.
* @return The names of all the children nodes.
* @throws XPathExpressionException the XPath expression exception
*/
public String[] getChildNames(String query) throws XPathExpressionException {
return getChildNames(query, root);
}
private String[] getChildNames(String query, Node qRoot) throws XPathExpressionException {
String[] names;
NodeList nodes = getElements(query + "/*", qRoot);
if (nodes == null) {
return null;
}
names = new String[nodes.getLength()];
for (int i = 0; i < names.length; i++) {
names[i] = nodes.item(i).getLocalName();
}
return names;
}
/**
* Get the text content of each node identified by the given XPath
* expression.
*
* @param query The XPath expression to evaluate.
* @return An array of each identified node's text content.
* @throws XPathExpressionException the XPath expression exception
*/
public String[] getNodeValues(String query) throws XPathExpressionException {
return getNodeValues(query, root);
}
private String[] getNodeValues(String query, Node qRoot) throws XPathExpressionException {
String[] result;
NodeList list = getElements(query, qRoot);
if (list == null) {
return null;
}
result = new String[list.getLength()];
for (int i = 0; i < list.getLength(); i++) {
result[i] = (list.item(i)).getTextContent();
}
return result;
}
/**
* Get the node set identified by the given XPath expression.
*
* @param query The XPath expression to evaluate.
* @return The set of nodes identified by the given expression.
* @throws XPathExpressionException the XPath expression exception
*/
public NodeList getElements(String query) throws XPathExpressionException {
return getElements(query, root);
}
private NodeList getElements(String query, Node qRoot) throws XPathExpressionException {
NodeList nodes = (NodeList) xpath.evaluate(query, qRoot, XPathConstants.NODESET);
if (nodes != null && nodes.getLength() > 0) {
return nodes;
} else {
return null;
}
}
/**
* Get the Node identified by the given XPath expression.
*
* @param query The XPath expression to evaluate.
* @return The identified Node.
* @throws XPathExpressionException the XPath expression exception
*/
public Node getElement(String query) throws XPathExpressionException {
return (Node) xpath.evaluate(query, root, XPathConstants.NODE);
}
}