//$Header: /cvsroot-fuse/mec-as2/39/mendelson/util/XPathHelper.java,v 1.1 2012/04/18 14:10:41 heller Exp $
package de.mendelson.util;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.jaxen.SimpleNamespaceContext;
import org.jaxen.XPath;
import org.jaxen.XPathSyntaxException;
import org.jaxen.dom.DOMXPath;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
/*
* Copyright (C) mendelson-e-commerce GmbH Berlin Germany
*
* This software is subject to the license agreement set forth in the license.
* Please read and agree to all terms before using this software.
* Other product and brand names are trademarks of their respective owners.
*/
/**
* Helper to get some values out of XML files, this could be reimplemented
* in XPATH syntax if a nice API exists. Using this class you could check existing
* parameters of XPATH pathes, get values of nodes ...
* @author S.Heller
* @version $Revision: 1.1 $
*/
public class XPathHelper {
private Logger logger = Logger.getAnonymousLogger();
/**Document to look into*/
private Document document = null;
/**Namespace to set to the xpath that is used*/
private SimpleNamespaceContext namespaceContext = null;
/**Parses the passed filename document and creates a DOM
*document
*@param filename Name of the xml file to parse
*/
public XPathHelper(String filename) throws Exception {
InputStream inStream = new FileInputStream(filename);
this.parse(new InputSource(inStream));
inStream.close();
}
public XPathHelper(InputSource source) throws Exception {
this.parse(source);
}
public XPathHelper(Document document) throws Exception {
this.parse(document);
}
public XPathHelper(InputStream inStream) throws Exception {
this.parse(new InputSource(inStream));
}
private void parse(InputSource source) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setIgnoringComments(true);
factory.setValidating(false);
DocumentBuilder builder = factory.newDocumentBuilder();
Document parseDocument = builder.parse(source);
this.parse(parseDocument);
}
private void parse(Document document) {
this.document = document;
//check if there are namespaces defined..add them to the XPath later
Element documentElement = this.document.getDocumentElement();
NamedNodeMap map = documentElement.getAttributes();
for (int i = 0; i < map.getLength(); i++) {
Node node = map.item(i);
if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
Attr attribute = (Attr) node;
String attributeName = attribute.getNodeName();
if (attributeName.startsWith("xmlns:")
&& attributeName.length() > 6) {
String uri = documentElement.getAttribute(attributeName);
String ns = attributeName.substring(6);
if (this.namespaceContext == null) {
this.namespaceContext = new SimpleNamespaceContext();
}
this.namespaceContext.addNamespace(ns, uri);
}
}
}
}
/**Adds a new, user defined namespace alias to the xpath processing. This is necessary
*for xml data that contains something like
*<semiramis xmlns="com.cisag.app.sales.obj.SalesOrder">
*...
*</semiramis>
*/
public void addNamespace(String ns, String uri) {
if (this.namespaceContext == null) {
this.namespaceContext = new SimpleNamespaceContext();
}
this.namespaceContext.addNamespace(ns, uri);
}
/**Gets the value of a node given by the node path,
*the node path has the syntax
* /value/value where every path could have a repeat in []
* like /value/value/value[3]/value, without a repeat you are
* looking for the 1th element
*@param nodePath Path to look for
*/
public String getValue(String nodePath) throws Exception {
try {
XPath xPath = new DOMXPath(nodePath);
if (this.namespaceContext != null) {
xPath.setNamespaceContext(this.namespaceContext);
}
return (xPath.stringValueOf(this.document));
} catch (XPathSyntaxException e) {
throw new Exception(e.getMultilineMessage());
}
}
/**Returns if a node of a passed nodepath exists in the actual document
*@param nodePath Path to look for
*/
public boolean pathExists(String nodePath) throws Exception {
XPath xPath = null;
try {
xPath = new DOMXPath(nodePath);
if (this.namespaceContext != null) {
xPath.setNamespaceContext(this.namespaceContext);
}
} catch (XPathSyntaxException e) {
throw new Exception(e.getMultilineMessage());
}
return (xPath.selectSingleNode(this.document) != null);
}
/**Counts the number of results for the passed path. This is useful to iterate
*on the results of an xpath if there could be more than one:
*<a>vv</a>
*<a>xy</a>
*<a>dd</a>
*
*will return 3 and its possible the gain the single branch values adding a
*a[1], a[2] or a[3] to the XPath.
*/
public int getNodeCount(String nodePath) throws Exception {
XPath xPath = null;
try {
xPath = new DOMXPath("count(" + nodePath + ")");
if (this.namespaceContext != null) {
xPath.setNamespaceContext(this.namespaceContext);
}
} catch (XPathSyntaxException e) {
throw new Exception(e.getMultilineMessage());
}
Object object = xPath.evaluate(this.document);
if (object == null) {
return (0);
}
//double is expected here
if (object instanceof Double) {
double counter = ((Double) object).doubleValue();
return ((int) counter);
}
//should not happen
return (0);
}
/**Returns a list of nodes of the passed xpath expression
*/
public List getNodes(String nodePath) throws Exception {
XPath xPath = null;
try {
xPath = new DOMXPath(nodePath);
if (this.namespaceContext != null) {
xPath.setNamespaceContext(this.namespaceContext);
}
} catch (XPathSyntaxException e) {
throw new Exception(e.getMultilineMessage());
}
Object object = xPath.evaluate(this.document);
if (object == null) {
return (new ArrayList());
}
if (object instanceof List) {
return ((List) object);
}
List returnList = new ArrayList();
returnList.add(object);
return (returnList);
}
public static void main(String[] args) {
try {
XPathHelper helper = new XPathHelper("c:/temp/test.xml");
//helper.addNamespace( "x", "com.cisag.app.sales.obj.SalesOrder" );
long start = System.currentTimeMillis();
System.out.println("nodesOld=" + helper.getNodeCount("/List/RECADV/SG16/SG22/DTM"));
System.out.println(System.currentTimeMillis() - start + "ms");
start = System.currentTimeMillis();
System.out.println("existsOld=" + helper.pathExists("/List/RECADV/SG16/SG22/DTM1"));
System.out.println(System.currentTimeMillis() - start + "ms");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}