Using JDK5 XPath functionality

Although JDK5 is available for quite some time I just recently used the builtin ‘XPath’ functionality. I wanted to check if a certain WSDL file contained certain tags and if the message style was set to ‘Document’ and not ‘RPC’. Now this seemed as a great oppertunity to use the XPath object so I started with the following code.
(Please note that this code is just for showing my issue, this is not how I actually would make it ;-) ). The base for this code I found here.

1
2
3
4
5
6
7
8
// Translate WSDl file to an InputSOurce
File xmlDocument = new File(new URI(fileName));
 
InputSource inputSource =
new InputSource(new FileInputStream(xmlDocument));
 
//Use inputsource as source for the Xpath evaluation of certain expressions
String doc = xPath.evaluate(//pre:definitions//pre:portType//pre:documentation”, inputSource);

After solving a namespace issue I was able to check for the tag. But doing the same sort of code for the second check

String msgStyle =
xPath.evaluate("//pre:definitions//pre:binding//soap:binding/@style",
inputSource);

I ran into this error:

java.io.IOException: Invalid argument
at java.io.FileInputStream.read(Native Method)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager$RewindableInputStream.read(XMLEntityManager.java:2622)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:997)
at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:184)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:798)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:148)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:250)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:292)
at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(XPathImpl.java:468)
at org.soacheck.impl.WsdlCheckerImpl.check2(WsdlCheckerImpl.java:191)
at org.soacheck.Processor.main(Processor.java:31)
————— linked to ——————
javax.xml.xpath.XPathExpressionException
at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(XPathImpl.java:475)
at org.soacheck.impl.WsdlCheckerImpl.check2(WsdlCheckerImpl.java:191)
at org.soacheck.Processor.main(Processor.java:31)
Caused by: java.io.IOException: Invalid argument
at java.io.FileInputStream.read(Native Method)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager$RewindableInputStream.read(XMLEntityManager.java:2622)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:997)
at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:184)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:798)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:148)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:250)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:292)
at com.sun.org.apache.xpath.internal.jaxp.XPathImpl.evaluate(XPathImpl.java:468)
… 2 more

I started to look for the error in my own code, maybe I did something wrong with the XPath object, but Googling for the error didn’t bring a solution rightaway. However, I did notice that a lot of examples of the XPath expression used a Document as input and not an InputSource. So I therefore rewrited the code to make it use a Document object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
DocumentBuilder docBuilder = null;
Document inputSource = null;
File sourceFile = null;
 
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
dbFactory.setIgnoringElementContentWhitespace(true);
dbFactory.setNamespaceAware(true); // never forget this!
 
docBuilder = dbFactory.newDocumentBuilder();
sourceFile = new File(new URI(fileName));
inputSource = docBuilder.parse(sourceFile);
 
XPathFactory factory = XPathFactory.newInstance();
XPath xPath = factory.newXPath();
 
String doc = xPath.evaluate(//pre:definitions//pre:portType//pre:documentation”, inputSource);
String msgStyle = xPath.evaluate(//pre:definitions//pre:binding//soap:binding/@style”, inputSource);

Now this code works like a charm! But the issue that remains is why? Apparently you can not ‘search’ an XML document twice with a Sax inputsource as source. I guess that make sense in some way, since SAX responds to events when reading the XML. But if this is true then I am surprised it didn’t say anything about it in the Javadoc (or I didn’t search hard enough?) and couldn’t there be made a more friendly error message pointing to a possible solution for this issue? If I am wrong about this, please let me know!

tags:

About Pascal Alma

Pascal started as an Oracle Developer in 1997 and developed numerous applications with Oracle Designer/Developer and PL/SQL. Since 2001 Pascal becomes more and more active with the development of software at the Java/J2EE platform. Nowadays Pascal is a senior JEE Developer/ Architect and has a lot of experience with several open source initiatives/ frameworks especially within the Enterprise Integration area. Besides these technical skills Pascal is a big Scrum enthusiastic.

3 Responses to Using JDK5 XPath functionality

  1. Pingback: Pascal’s Blog » Create an ADF ViewObject based on BPEL’s HumanWorkflow Tasklist

  2. Paul Campbell says:

    I had a similiar result. I think that you are correct that the original method fails because it uses a SAX parser and the docBuilder.parse is DOM.
    Thanks for your suggestion.

    I am a little disapointed in the execution time.

    I was trying to replace a memory hog that groveled thru strings with
    XPath, but it seems to be an order of magnitude slower, 20 ms went to 300ms

  3. sandeep says:

    good call… documnet obj works like a charm