user2816085
user2816085

Reputation: 655

xpath for xml document with varying depth

I have an xml document where there is fixed structure but depth is varying for example :-

  1. It has main node <project>.
  2. it has child node <namespace> that may be repeated multiple times. And there may come some new tags before or after <namespace>.
<project>
 <newtag>
 <namespace>
   <namespace>
     ..........
   </namespace>
 </namespace>
 </newtag>
</project>
  1. After multiple namespace there are two more tags of my interest <querySubject> and <queryItem>

I am searching for a text in queryItem tag using a particular XPATH :-

/project/namespace/namespace/querySubject/queryItem[contains(., 'searchTerm')]/ancestor-or-self::*/name

My Xpath is working fine for a particular structure given below :-

<project>
<namespace>
        <name locale="en">Test</name>
        <lastChanged>2016-01-12T12:42:46</lastChanged>
            <namespace>
            <name locale="en">Database Layer</name>
                <querySubject status="valid">
                <name locale="en">qskxyz</name>
                    <queryItem>
                    <name locale="en">qixyz</name>
                        <hello>searchTerm</hello>
                    </queryItem>
                </querySubject>
            </namespace>
 </namespace>
 <namespace>
        <name locale="en">Test</name>
        <lastChanged>2016-01-12T12:42:46</lastChanged>
            <namespace>
            <name locale="en">Database Layer</name>
                <querySubject status="valid">
                <name locale="en">qsxyz</name>
                    <queryItem>
                    <name locale="en">myName</name>
                        <hello>...Hi there..</hello>
                    </queryItem>
                </querySubject>
            </namespace>
 </namespace>
 </project>

but not working if there is change as described in above points. Any suggestion

EDIT 1.

There was some miss in my observation

My actual project tag is

<project containsDynamicContent="false" xmlns="http://www.developer.cognos.com/schemas/bmt/60/7" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.developer.cognos.com/schemas/bmt/60/7 BMTModelSpecification.xsd">

However in dev I am taking simple <project></project>

This is affecting and my Xpath is not working. Any suggestion I tried below Xpath but this too is not working and I can not change my xml tag.. I have already tried this xpath :-

//namespace//querySubject/queryItem[contains(.,'searchTerm')]/ancestor-or-self::*/name 

Upvotes: 3

Views: 324

Answers (1)

TT.
TT.

Reputation: 16137

Basically, the XPath expression is:

/x:project//x:namespace//x:querySubject/x:queryItem[contains(.,'searchTerm')]/ancestor-or-self::*/x:name

Then you need to associate the namespace http://www.developer.cognos.com/schemas/bmt/60/7 with the prefix x.


I'm going to leave you with a snippet in Java (1.7) as an example. This registers a NamespaceContext with the XPath expression, which resolves a namespace for a prefix (x in this case). The snippet is a bare-bone example, it doesn't even check which prefix is passed to NamespaceContext.getNamespaceURI. Typical implementations use a map to map the URI to a prefix.

Other development environments should have similar functionality.


import java.io.StringReader;
import java.util.Iterator;
import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.*;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class XPathInXmlns {
    private static final String xml=
"<project containsDynamicContent=\"false\" xmlns=\"http://www.developer.cognos.com/schemas/bmt/60/7\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.developer.cognos.com/schemas/bmt/60/7 BMTModelSpecification.xsd\">"+
"   <namespace>"+
"           <name locale=\"en\">Test</name>"+
"           <lastChanged>2016-01-12T12:42:46</lastChanged>"+
"               <namespace>"+
"               <name locale=\"en\">Database Layer</name>"+
"                   <querySubject status=\"valid\">"+
"                   <name locale=\"en\">qskxyz</name>"+
"                       <queryItem>"+
"                       <name locale=\"en\">qixyz</name>"+
"                           <hello>searchTerm</hello>"+
"                       </queryItem>"+
"                   </querySubject>"+
"               </namespace>"+
"    </namespace>"+
"    <namespace>"+
"           <name locale=\"en\">Test</name>"+
"           <lastChanged>2016-01-12T12:42:46</lastChanged>"+
"               <namespace>"+
"               <name locale=\"en\">Database Layer</name>"+
"                   <querySubject status=\"valid\">"+
"                   <name locale=\"en\">qsxyz</name>"+
"                       <queryItem>"+
"                       <name locale=\"en\">myName</name>"+
"                           <hello>...Hi there..</hello>"+
"                       </queryItem>"+
"                   </querySubject>"+
"               </namespace>"+
"    </namespace>"+
" </project>";

    private static final String xpathExpr=
"/x:project//x:namespace//x:querySubject/x:queryItem[contains(.,'searchTerm')]/ancestor-or-self::*/x:name/text()";

    public static void main(String[] args) {
        try {
            XPath xpath = XPathFactory.newInstance().newXPath();
            xpath.setNamespaceContext(new NamespaceContext() {
                @Override
                public Iterator getPrefixes(String namespaceURI) {
                    return null;
                }
                @Override
                public String getPrefix(String namespaceURI) {
                    return null;
                }
                @Override
                public String getNamespaceURI(String prefix) {
                    return "http://www.developer.cognos.com/schemas/bmt/60/7";
                }
            });
            XPathExpression expr = xpath.compile(xpathExpr);
            NodeList nodeList = (NodeList) expr.evaluate(new InputSource(new StringReader(xml)),XPathConstants.NODESET);
            for( int i = 0; i != nodeList.getLength(); ++i )
                System.out.println(nodeList.item(i).getNodeValue());
        } catch (XPathExpressionException e) {
            e.printStackTrace();
        }
    }
}

Output:

Test
Database Layer
qskxyz
qixyz

Upvotes: 1

Related Questions