You need to use XPath expressions to
select objects from a complex object
graph referencing the contents of a Map
and using
expressions with variable references.
Use Jakarta Commons JXPath to select objects from a collection using
XPath queries. The following example uses Commons Digester to parse
an XML file into an object graph, and selects
Planet
objects with a radius greater than 5000:
import org.apache.commons.digester.Digester; import org.apache.commons.digester.xmlrules.DigesterLoader; import org.apache.commons.jxpath.JXPathContext; List planets = new ArrayList( ); // Parse Planet XML into a List of Planet objects InputStream input = getClass( ).getResourceAsStream("./planets.xml"); URL rules = getClass( ).getResource("./planet-digester-rules.xml"); Digester digester = DigesterLoader.createDigester(rules); digester.push(planets); digester.parse( input ); // Select all planets with a radius greater than 5000 System.out.println( "Planet Name where radius > 5000"); JXPathContext context = JXPathContext.newContext( planets ); Iterator iterator = context.iterate(".[@radius > 5000]/name"); while( iterator.hasNext( ) ) { Object o = (Object) iterator.next( ); System.out.println( "Object: " + o); }
The Planet
objects are filtered and the names of
planets with sufficient radii are printed to the console:
Planet Name where radius > 5000 Object: Venus Object: Saturn
This object graph was created from an XML document that contains a
list of planets and their physical properties including mass, radius,
atmospheric composition, lunar population, and orbital distance and
period. Commons Digester (from Chapter 6) is
used to parse this XML document to a list of
Planet
objects. The following XML document,
planets.xml
, was parsed in the previous example:
<planets> <planet name="Venus" mass="4.869e+24" radius="6051.8"> <orbit distance="108200000" period="224.701"/> <atmosphere meanTemp="482" pressure="92"> <component symbol="CO2" percentage="96"/> <component symbol="N" percentage="3"/> <component symbol="Other" percentage="1"/> </atmosphere> </planet> <planet name="Mars" mass="6.421e+23" radius="3397.2"> <orbit distance="227940000" period="686.98"/> <atmosphere meanTemp="-63" pressure="0.007"> <component symbol="CO2" percentage="95.32"/> <component symbol="N2" percentage="2.7"/> <component symbol="Ar" percentage="1.6"/> </atmosphere> <moon>Phobos</moon> <moon>Deimos</moon> </planet> <planet name="Saturn" mass="5.688e+26" radius="60268"> <orbit distance="1429400000" period="29.458"/> <atmosphere meanTemp="-125" pressure="1.4"> <component symbol="H" percentage="97"/> <component symbol="He" percentage="3"/> </atmosphere> <moon>Pan</moon> <moon>Atlas</moon> <moon>Prometheus</moon> <moon>Pandora</moon> <moon>Epimetheus</moon> <moon>Janus</moon> <moon>Mimas</moon> </planet> </planets>
To parse this XML document, the following Digester rules are passed
to DigesterLoader.createDigester()
. This digester rule-set creates a
Planet
, Orbit
, and
Atmosphere
object for each planet.
Moon
objects are created and added to
Planet
objects using the addMoon( )
method on Planet
. Individual compounds
in an atmosphere are added to an
Atmosphere
’s
component
Map
using
addComponent( )
. The following XML document contains the
contents of the planet-digester-rules.xml
file
used in the previous example:
<digester-rules> <pattern value="planets/planet"> <object-create-rule classname="Planet"/> <set-properties-rule/> <pattern value="orbit"> <object-create-rule classname=" Orbit"/> <set-properties-rule/> <set-next-rule methodname="setOrbit" paramtype=" Orbit"/> </pattern> <pattern value="atmosphere"> <object-create-rule classname="Atmosphere"/> <set-properties-rule/> <pattern value="component"> <call-method-rule methodname="addComponent" paramcount="2" paramtypes="java.lang.String,java.lang.Double"/> <call-param-rule attrname="symbol" paramnumber="0"/> <call-param-rule attrname="percentage" paramnumber="1"/> </pattern> <set-next-rule methodname="setAtmosphere" paramtype=" Atmosphere"/> </pattern> <call-method-rule pattern="moon" methodname="addMoon" paramtypes="java.lang.String" paramcount="0"/> <set-next-rule methodname="add" paramtype="java.lang.Object"/> </pattern> </digester-rules>
XPath expressions can be parameterized by referencing a variable
name: $variable
. The following example
references a variable $moonName
, which is
populated by calling declareVariable( )
on
context.getVariables( )
:
System.out.println( "Planet Name where a moon is named Deimos"); context.getVariables( ).declareVariable("moonName", "Deimos"); iterator = context.iterate("./moons[. = $moonName]/../name"); while( iterator.hasNext( ) ) { String name = (String) iterator.next( ); System.out.println( "Planet Namet: " + name); }
This example selects the name of a planet with a moon named “Deimos.” The results of the previous example are printed below:
Planet Name where a moon is named Deimos Planet Namet: Mars
Planet.getAtmosphere( ).getComponents( )
returns a
Map
with element symbols as keys. The following
example selects every planet with more than a 2% Helium atmosphere:
System.out.println( "Planet where Helium percentage greater than 2"); iterator = context.iterate("./atmosphere/components/He[.>2]/../../.."); while( iterator.hasNext( ) ) { Planet p = (Planet) iterator.next( ); System.out.println( "Planet: " + p.getName( )); }
To select every planet with more than a 2% Helium atmosphere, the
XPath expression in the previous example references a specific key in
the components Map
as if it were a nested element.
components/He[.>2]
will evaluate to
true
if getComponents( ).get("He")
is a number larger than 2. The previous code
determines that Saturn is the only one of these three planets with
more than 2% Helium:
Planet where Helium percentage greater than 2 Planet: Saturn
The following example prints a list of each moon and the corresponding planet using a reference to a variable in an XPath expression:
System.out.println( "All of the Moon Names"); iterator = context.iterate("./moons"); while( iterator.hasNext( ) ) { String moon = (String) iterator.next( ); context.getVariables( ).declareVariable("moonName", moon); String planet = (String) context.getValue("./moons[. = $moonName]/../name"); System.out.println( "Moon: " + moon + ", Planet: " + planet); }
The previous example shows that a JXPathContext
can be reused. This example iterates through each moon and finds the
name of the planet corresponding to each moon using the results of
the first expression to populate a variable in the second expression.
The XPath expression, ./moons[. =
$moonName]/../name
, contains a reference to the variable
$moonName
, which is set by passing a variable name
and value to the declareVariable( )
method on JXPathContext
.
This example prints each moon and planet to the console as follows:
All of the Moon Names Moon: Phobos, Planet: Mars Moon: Deimos, Planet: Mars Moon: Pan, Planet: Saturn Moon: Atlas, Planet: Saturn Moon: Prometheus, Planet: Saturn Moon: Pandora, Planet: Saturn Moon: Epimetheus, Planet: Saturn Moon: Janus, Planet: Saturn Moon: Mimas, Planet: Saturn
There is much more to JXPath including object creation and the ability to set properties using XPath expressions; for more information about using JXPath to access maps, collections, servlet contexts, and DOM/JDOM Documents, see the JXPath User’s Guide (http://jakarta.apache.org/commons/jxpath/users-guide.html).
3.142.199.181