Reputation: 113
I want to read XML data using XPath in Java.
I have the next XML file named MyXML.xml
:
<?xml version="1.0" encoding="iso-8859-1" ?>
<REPOSITORY xmlns:LIBRARY="http://www.openarchives.org/LIBRARY/2.0/"
xmlns:xsi="http://www.w3.prg/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.openarchives.org/LIBRARY/2.0/ http://www.openarchives.org/LIBRARY/2.0/LIBRARY-PHM.xsd">
<repository>Test</repository>
<records>
<record>
<ejemplar>
<library_book:book
xmlns:library_book="http://www.w3c.es/LIBRARY/book/"
xmlns:book="http://www.w3c.es/LIBRARY/book/"
xmlns:bookAssets="http://www.w3c.es/LIBRARY/book/"
xmlns:bookAsset="http://www.w3c.es/LIBRARY/book/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3c.es/LIBRARY/book/ http://www.w3c.es/LIBRARY/replacement/book.xsd">
<book:bookAssets count="1">
<book:bookAsset nasset="1">
<book:bookAsset.id>value1</book:bookAsset.id>
<book:bookAsset.event>
<book:bookAsset.event.id>value2</book:bookAsset.event.id>
</book:bookAsset.event>
</book:bookAsset>
</book:bookAssets>
</library_book:book>
</ejemplar>
</record>
</records>
</REPOSITORY>
I want access to value1
and value2
values. For this, I try this:
// Standard of reading a XML file
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder;
Document doc = null;
XPathExpression expr = null;
builder = factory.newDocumentBuilder();
doc = builder.parse("MyXML.xml");
// Create a XPathFactory
XPathFactory xFactory = XPathFactory.newInstance();
// Create a XPath object
XPath xpath = xFactory.newXPath();
expr = xpath.compile("//REPOSITORY/records/record/ejemplar/library_book:book//book:bookAsset.event.id/text()");
Object result = expr.evaluate(doc, XPathConstants.STRING);
System.out.println("RESULT=" + (String)result);
But I don't get any results. Only prints RESULT=
.
¿How to access to value1
and value2
values?. ¿What is the XPath filter to apply?.
Thanks in advanced.
I'm using JDK6.
Upvotes: 0
Views: 1601
Reputation: 306
One approach is to implement a name space context like:
public static class UniversalNamespaceResolver implements NamespaceContext {
private Document sourceDocument;
public UniversalNamespaceResolver(Document document) {
sourceDocument = document;
}
public String getNamespaceURI(String prefix) {
if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
return sourceDocument.lookupNamespaceURI(null);
} else {
return sourceDocument.lookupNamespaceURI(prefix);
}
}
public String getPrefix(String namespaceURI) {
return sourceDocument.lookupPrefix(namespaceURI);
}
public Iterator getPrefixes(String namespaceURI) {
return null;
}
}
And then use it like
xpath.setNamespaceContext(new UniversalNamespaceResolver(doc));
You also need to move up all the namespace declarations to the root node (REPOSITORY). Otherwise it might be a problem if you have namespace declarations on two different levels.
Upvotes: 0
Reputation: 25613
You are having problems with namespaces, what you can do is
local-name()
functionSolution 1 implies implementing a NamespaceContext
that maps namespaces names and URIs and set it on the XPath
object before querying.
Solution 2 is easy, you just need to change your XPath (but depending on your XML you may fine-tune your XPath to be sure to select the correct element):
XPath xpath = xFactory.newXPath();
expr = xpath.compile("//*[local-name()='bookAsset.event.id']/text()");
Object result = expr.evaluate(doc, XPathConstants.STRING);
System.out.println("RESULT=" + result);
You can take a look at the following blog article to better understand the uses of namespaces and XPath in Java (even if old)
Upvotes: 1
Reputation: 1170
Try
Object result = expr.evaluate(doc, XPathConstants.NODESET);
// Cast the result to a DOM NodeList
NodeList nodes = (NodeList) result;
for (int i=0; i<nodes.getLength();i++){
System.out.println(nodes.item(i).getNodeValue());
}
Upvotes: 0