I have an XML file of the following structure:
<?xml version="1.0" encoding="utf-8"?>
<root>
<ArrayOfLocationDTO xmlns:xsi="foo1" xmlns:xsd="foo2" xmlns="foo3">
<LocationDTO ~some data~>~child nodes etc~</LocationDTO>
<LocationDTO ~some data~>~child nodes etc~</LocationDTO>
... ... ...
<LocationDTO ~some data~>~child nodes etc~</LocationDTO>
<LocationDTO ~some data~>~child nodes etc~</LocationDTO>
</ArrayOfLocationDTO>
</root>
I’m trying to grab all ‘LocationDTO’ from there. My code looks like that:
XPath xpath = XPathFactory.newInstance().newXPath();
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setNamespaceAware(true);
DocumentBuilder builder = builderFactory.newDocumentBuilder();
File XMLPath=new File(Environment.getExternalStorageDirectory(), "XMLSource.xml");
Document document = builder.parse(XMLPath);
NodeList nodes = (NodeList) xpath.evaluate("//LocationDTO", document, XPathConstants.NODESET);
int count=nodes.getLength();
My problem is that the code finds nothing unless I remove ‘ArrayOfLocationDTO’ manually from XML source.
Why ArrayOfLocationDTO prevents my code from working properly and how can I make it work without programmatical removal of ArrayOfLocationDTO (I consider the latter a sort of ‘dirty solution’)?
ArrayOfLocationDTO has an attribute xmlns=”foo3″. This attribute is one of the very few XML attributes that have a special meaning: specifically it means that ArrayOfLocationDTO and each tag inside it has a namespace “foo3” (each XML tag has a local name and – optionally – a namespace – which is a string introduced by one of xmlns syntaxes).
This means that your document has NO tag of name “LocationDTO”. “LocationDTO” is only a local part of the name.
You have two choices:
find tags by their local names, using function local-name: //*[local-name()=’LocationDTO’]; this is by far the quickest solution in your case (a simple search, small document, a single namespace)
establish a namespace context (using, if I remember correctly, setNamespaceContext) that binds “foo3” to an arbitrary prefix (eg. “f”) and use the query: //f:LocationDTO