In this java example, we will learn XPath namespace resolution into an XML file using NamespaceContext which has namespace declarations and respective usages.
Namespace added XML file
I have created sample.xml
file and put in on classpath.
<ns2:bookStore xmlns:ns2="http://bookstore.com/schemes"> <ns2:book id="1"> <ns2:name>Data Structure</ns2:name> </ns2:book> <ns2:book id="2"> <ns2:name>Java Core</ns2:name> </ns2:book> </ns2:bookStore>
Implement NamespaceContext to create namespace resolver
This namespace resolver can be used with any XML file where namespace definitions have been used. It searches for namespace declarations for any given namespace prefix – passed as parameter – inside XML document itself. So no need to create namespace mapping separately.
public class NamespaceResolver implements NamespaceContext { //Store the source document to search the namespaces private Document sourceDocument; public NamespaceResolver(Document document) { sourceDocument = document; } //The lookup for the namespace uris is delegated to the stored 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); } @SuppressWarnings("rawtypes") public Iterator getPrefixes(String namespaceURI) { return null; } }
Using NamespaceResolver and apply XPath
Now we are ready to apply xpath expression over XML file.
//Want to read all book names from XML ArrayList<String> bookNames = new ArrayList<String>(); //Parse XML file DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(new FileInputStream(new File("sample.xml"))); //Get XPath expression XPathFactory xpathfactory = XPathFactory.newInstance(); XPath xpath = xpathfactory.newXPath(); xpath.setNamespaceContext(new NamespaceResolver(doc)); XPathExpression expr = xpath.compile("//ns2:bookStore/ns2:book/ns2:name/text()"); //Search XPath expression Object result = expr.evaluate(doc, XPathConstants.NODESET); //Iterate over results and fetch book names NodeList nodes = (NodeList) result; for (int i = 0; i < nodes.getLength(); i++) { bookNames.add(nodes.item(i).getNodeValue()); } //Verify book names System.out.println(bookNames);
Output of above program is:
[Data Structure, Java Core]
Complete Source Code for XPath Namespace Resolution
This is the complete sourcecode of above example.
import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; import java.util.Iterator; import javax.xml.XMLConstants; import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; public class Main { public static void main(String[] args) throws Exception { //Want to read all book names from XML ArrayList<String> bookNames = new ArrayList<String>(); //Parse XML file DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(new FileInputStream(new File("sample.xml"))); //Get XPath expression XPathFactory xpathfactory = XPathFactory.newInstance(); XPath xpath = xpathfactory.newXPath(); xpath.setNamespaceContext(new NamespaceResolver(doc)); XPathExpression expr = xpath.compile("//ns2:bookStore/ns2:book/ns2:name/text()"); //Search XPath expression Object result = expr.evaluate(doc, XPathConstants.NODESET); //Iterate over results and fetch book names NodeList nodes = (NodeList) result; for (int i = 0; i < nodes.getLength(); i++) { bookNames.add(nodes.item(i).getNodeValue()); } //Verify book names System.out.println(bookNames); } } class NamespaceResolver implements NamespaceContext { //Store the source document to search the namespaces private Document sourceDocument; public NamespaceResolver(Document document) { sourceDocument = document; } //The lookup for the namespace uris is delegated to the stored 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); } @SuppressWarnings("rawtypes") public Iterator getPrefixes(String namespaceURI) { return null; } }
Let me know of your questions in comments section.
Happy Learning !!
Reference: http://www.ibm.com/developerworks/library/x-nmspccontext/
One weakness with your approach comes from the assumption that the prefix has any real meaning. In fact, the namespace prefix is arbitrary. A document could be written with the prefix ns3 instead of ns2, which would still be valid according to a schema, but your code would fail because you’ve hard-coded the prefix. Is there really a way to get around the fact that you have to know the URI portion of the namespace to reliably parse these documents?
Hi, in my case my api returns the response where name spaces are dynamic i.e the number of name spaces present in the xml is not fixed. In that case what should be the xpath expression?
Is there any way to ignore the name space in while providing it in the xpath
Thank you for the solution, worked like a charm.
Btw is there a way i can ignore the namespace while providing the xpath?
I don’t understand what part of the flow you use the namspece.
Thank You so much – Great example, neat and crisp, works like a charm
Good example, excellent explained! This example helped me a lot! Thanks!