WebLogic XPath API lets you match XPath expressions against an XML document, represented either as a DOM tree or an XMLInputStream. The API is contained in the weblogic.xml.xpath.* package. Though the XPath syntax and semantics follow the W3C standard, there is still no standard Java API for manipulating XPath expressions, so this is a welcome API.
18.6.1 Using the API with a DOM
To use the API, construct DOMXPath instances representing your XPath. Here are a few examples:
DOMXPath threeDebt = new DOMXPath("sum(//co[@type='3']/debt)"); DOMXPath haveFirst = new DOMXPath("count(//co[@type='1']) > 0"); DOMXPath biggestDebt = new DOMXPath("//co[debt > 1000]/debt");
We will use the following XML as test input:
100 1000 2000
You can match the XPath expressions against either a DOM node or the entire document itself. Use a node if you intend to just search a portion of the document. To evaluate the XPath expression, you must invoke one of the following evaluate methods on the DOMXPath instance:
public boolean evaluateAsBoolean(Document|Node); public java.util.Set evaluateAsNodeset(Document|Node); public double evaluateAsNumber(Document|Node); public String evaluateAsString(Document|Node);
The actual evaluate method you invoke will depend on the type of the expected result(s) of your XPath expression. For example, we would invoke the earlier XPath expressions as follows:
/** evaluate the total third-world debt */ double e_debt = threeDebt.evaluateAsNumber(doc); /** evaluate if there are any developed countries */ boolean e_haveFirst = haveFirst.evaluateAsBoolean(doc); /** find the countries with a serious debt problem */ Set biggest = biggestDebt.evaluateAsNodeset(doc);
The evaluateAsNodeSet( ) method returns a set of org.w3c.dom.Node objects that match the XPath expression, so, you could iterate over the set of nodes as follows:
if (biggest!= null) { Iterator i = biggest.iterator( ); while (i.hasNext( )) { Node n = (Node)i.next( ); // Process the node } }
The result of running this little test will indicate that the total third-world debt (e_debt) is 3000, that it is true that there is a first-world country, and that there is one member in the set of countries with a major debt problem.
18.6.2 Using the API with a Stream
Matching XPath expressions against an XML document that is read as an XML stream is just a little more involved. You would expect this because the document that you are matching against is read only incrementally. Thus, instead of waiting for the XPath expression to complete its evaluation, the API lets you register a set of "observers" before the XML stream is processed. These observers then are invoked whenever an XPath match is found as you incrementally parse the XML stream, in the order in which the observers were assigned. Because you're going to match an XPath expression against an XML stream, you need to create a StreamXPath instance (instead of a DOMXPath object) to represent your XPath expression:
StreamXPath pops = new StreamXPath ("//co/pop");
Now you must create an XPathStreamFactory instance and register one or more observers that are invoked whenever something within the XML stream matches the XPath expression:
XPathStreamFactory factory = new XPathStreamFactory( ); factory.install(pops, new XPathStreamObserver ( ) { public void observe(XMLEvent event) { System.out.println("Population event matched: "+event); } public void observeAttribute(StartElement e, Attribute a) {} //ignore public void observeNamespace(StartElement e, Attribute a) {} //ignore });
In this case, we've registered an observer that responds to any XML events that match the XPath expression. This means that as we pull events of the XML stream, WebLogic automatically calls the appropriate observe( ) methods whenever an XML event matching the XPath expression //co/pop is found. Remember, if you configure a StreamXPath instance with multiple observers, they will be called (during the parse) in the order in which they were installed.
Once you've installed the observers with the XPath expression, you then can initiate the evaluation. To achieve this, you need to simply use the XPathStreamFactory instance to construct an XML stream that can trigger the XPath observers, whenever you pull XML events that may match the XPath expression. In fact, the XPathStreamFactory instance provides the createStream( ) method, which accepts a single parameter: an XMLInputStream or an XMLOutputStream object. This method then returns an XML stream that can match the events in the source stream with the installed XPath observers. The following example shows how to enable XPath matching on an XML stream:
//src represents the location of an XML document XMLInputStream sourceStream = XMLInputStreamFactory.newInstance( ).newInputStream(new File(src)); XMLInputStream matchingStream = factory.createStream(sourceStream);
Now when you iterate over this XML stream, you get the same XML events as if you had iterated over the source stream, but in addition, the events are matched against the configured observers and the appropriate observe( ) methods are invoked. The following example shows how you would evaluate the XPath expression against the source stream:
while(matchingStream.hasNext( )) { XMLEvent event = matchingStream.next( ); // Do nothing if you are only interested in the XPath observations }
As you can see, we simply pull XML events from the stream the configured observers are executed transparently during this iteration. Note that because the Streaming API observes a set of events, a node such as debt will have two events associated with it (i.e., the start and end events). Both of these events will match the XPath expression, and both will trigger the appropriate observe( ) methods.
One of the disadvantages of using the Streaming XPath API is that you cannot use the full XPath expression syntax. For instance, if you attempt to match the following XPath expression against an XML stream, you will surely encounter a weblogic.xml.xpath.XpathUnsupportedException:
StreamXPath cost = new StreamXPath ("//co[debt > 1000]/debt");
The reason should be obvious. Since the Streaming XPath API iterates over a stream of XML events without any "look ahead" capability, it cannot possibly match against child elements. For this reason, you cannot use the child axis in the XPath predicate. The same reasoning can be applied to several other XPath expressions, leading to the following natural limitations:
Introduction
Web Applications
Managing the Web Server
Using JNDI and RMI
JDBC
Transactions
J2EE Connectors
JMS
JavaMail
Using EJBs
Using CMP and EJB QL
Packaging and Deployment
Managing Domains
Clustering
Performance, Monitoring, and Tuning
SSL
Security
XML
Web Services
JMX
Logging and Internationalization
SNMP