XPath local-name example
Continuing on the series of examples about XPath
, we will see how we can use the local-name function
in Java. We use this XPath
function we need to work with namespaces.
What are namespaces?
Namespaces are used to avoid conflicts in the tag-names. The tags have a prefix defined by the xmlns
attribute(short for XML namespace).
Let’s see an example of an XML file with namespace:
<cr:cricketers xmlns:cr="http://www.example.com/"> <cr:cricketer type="righty"> <name>MS Dhoni</name> <role>Captain</role> <position>Wicket-Keeper</position> </cr:cricketer> </cr:cricketers>
The XPath
functions we have been discussing so far for selecting nodes are useful for querying the XML
when the XML has default namespace. However, if the XML
has a namespace defined and the XML
the query won’t return any result at all.
Consider the example below:
The XML
file has a namespace, and the tags are appended with a prefix.
cricketTeam_info.xml:
<?xml version="1.0" encoding="UTF-8"?> <cr:cricketers xmlns:cr="http://www.example.com/"> <cr:cricketer type="righty"> <name>MS Dhoni</name> <role>Captain</role> <position>Wicket-Keeper</position> </cr:cricketer> <cr:cricketer type="lefty"> <name>Shikhar Dhawan</name> <role> Batsman</role> <position>Point</position> </cr:cricketer> <cr:cricketer type="righty"> <name>Virat Kohli</name> <role>Batsman</role> <position>cover</position> </cr:cricketer> <cr:cricketer type="righty"> <name>Shami</name> <role>Bowler</role> <position>SquareLeg</position> </cr:cricketer> <cr:cricketer type="lefty"> <name>Zaheer Khan</name> <role>Bowler</role> <position>FineLeg</position> </cr:cricketer> </cr:cricketers>
Let’s consider the below code snippet. It should display the name of the first cricketer node.
XPathExpression expr = xpath.compile("//cricketer/name/text()"); String name = (String) expr.evaluate(doc, XPathConstants.STRING); System.out.println("The cricketer name is : " + name);
Output:
The cricketer name is :
As you can see, since there is no namespace configured in the XPath expression, we don’t find any matching nodes. The XPath Expression is looking for default namespace but the document is with a different namespace.
local-name()
function to the rescue!
To resolve this problem of namespaces we have to use the local-name()
function. The local-name()
function ignores the namespace and returns the query results as if the XML
did not have any namespace.
Try to avoid
local-name()
when you have conflicting tag names.Consider implementing NamespaceContext for such a case.Let’s look at an example to see how to use the local-name()
function:
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; public class XpathLocalFunctionDemo { public static void main(String[] args) throws Exception { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); documentBuilderFactory.setNamespaceAware(true); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document doc = documentBuilder.parse("src/cricketTeam_info.xml"); XPathFactory xpathFactory = XPathFactory.newInstance(); XPath xpath = xpathFactory.newXPath(); XPathExpression expr = xpath.compile("//*[local-name()='cricketer']/name/text()"); String type = (String) expr.evaluate(doc, XPathConstants.STRING); System.out.println("The cricketer name is : " + type); } }
Output:
The cricketer name is : MS Dhoni
Once the XPath
query ignored the namespace prefix, the XPath Expression returns the expected answer.
Conclusion:
Here we tried to understand the effect of namespaces on XPath
querying and how we can circumvent the effect of the same while querying the XML
document in a simple manner.
You can download the source code of this example here: XPathLocalFunctionDemo.zip