This example assumes the following class is already on your CLASSPATH:
Here is an example of using Apache Xalan with Groovy to read an existing XML file:
// require(groupId:'xalan', artifactId:'xalan', version:'2.6.0')
import org.apache.xpath.XPathAPI
import javax.xml.parsers.DocumentBuilderFactory
messages = []
def processCar(car) {
def make = XPathAPI.eval(car, '@make').str()
def country = XPathAPI.eval(car, 'country/text()').str()
def type = XPathAPI.eval(car, 'record/@type').str()
messages << make + ' of ' + country + ' has a ' + type + ' record'
}
def builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
def inputStream = new ByteArrayInputStream(XmlExamples.CAR_RECORDS.bytes)
def records = builder.parse(inputStream).documentElement
XPathAPI.selectNodeList(records, '//car').each{ processCar(it) }
assert messages == [
'Holden of Australia has a speed record',
'Peel of Isle of Man has a size record',
'Bugatti of France has a price record'
]
|
Here is an example of using Jaxen with Groovy to read an existing XML file:
// require(groupId:'jaxen', artifactId:'jaxen', version:'1.1-beta-10')
import org.jaxen.dom.DOMXPath
import javax.xml.parsers.DocumentBuilderFactory
messages = []
def processCar(car) {
def make = new DOMXPath('@make').stringValueOf(car)
def country = new DOMXPath('country/text()').stringValueOf(car)
def type = new DOMXPath('record/@type').stringValueOf(car)
messages << make + ' of ' + country + ' has a ' + type + ' record'
}
def builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
def inputStream = new ByteArrayInputStream(XmlExamples.CAR_RECORDS.bytes)
def records = builder.parse(inputStream).documentElement
new DOMXPath('//car').selectNodes(records).each{ processCar(it) }
assert messages == [
'Holden of Australia has a speed record',
'Peel of Isle of Man has a size record',
'Bugatti of France has a price record'
]
|
Note: many libraries (e.g. DOM4J, JDOM, XOM) bundle or provide optional support for Jaxen. You may not need to download any additional JARs to use it.
If you are using Java 5 and above, you don't need to use the standalone Xalan jar but instead can use the now built-in XPath facilities:
import javax.xml.xpath.*
def xpath = XPathFactory.newInstance().newXPath()
def nodes = xpath.evaluate( '//car', records, XPathConstants.NODESET )
nodes.each{
def make = xpath.evaluate( '@make', it )
def country = xpath.evaluate( 'country/text()', it )
def type = xpath.evaluate( 'record/@type', it )
messages << "$make of $country has a $type record"
}
|
Inspired by this example, here is how to use XPath to determine which groups include all three of alan, paul and ivan for this graph representing group membership.

Picture source: http://stage.vambenepe.com/pages/graph.png
First, here is the XML data capturing the group membership information:
def xml = ''' <doc> <person name="alan"><g>1</g><g>2</g><g>4</g></person> <person name="marc"><g>1</g><g>2</g><g>3</g></person> <person name="paul"><g>2</g><g>3</g><g>4</g></person> <person name="ivan"><g>2</g><g>4</g></person> <person name="eric"><g>4</g></person> </doc> ''' |
Here is how to check that groups 2 and 4 are the groups in question using the built-in XPath capabilities of Java 5 and above:
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.xpath.*
xpath = '''
/doc/person[@name="alan"]/g
[.=/doc/person[@name="paul"]/g]
[.=/doc/person[@name="ivan"]/g]
'''
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
doc = builder.parse(new ByteArrayInputStream(xml.bytes))
expr = XPathFactory.newInstance().newXPath().compile(xpath)
nodes = expr.evaluate(doc, XPathConstants.NODESET)
assert nodes.collect { node -> node.textContent } == ['2', '4']
|
And you can refactor your XPath Expression with something like:
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.xpath.*
groupsOf = { name -> "/doc/person[@name='$name']/g" }
xpath = "${groupsOf 'alan'}[.=${groupsOf 'paul'}][.=${groupsOf 'ivan'}]"
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
doc = builder.parse(new ByteArrayInputStream(xml.bytes))
expr = XPathFactory.newInstance().newXPath().compile(xpath)
nodes = expr.evaluate(doc, XPathConstants.NODESET)
assert nodes.collect { node -> node.textContent } == ['2', '4']
|
Of course, you can also do this without XPath by using Groovy's GPath facilities as follows:
def root = new XmlParser().parseText(xml)
Set groups = root.person.g.collect{ it.text() }
assert groups.findAll{ group ->
root.person.g.findAll{
it.text() == group
}.'..'.'@name'.containsAll(['alan', 'paul', 'ivan'])
} == ['2', '4']
|