1

I am having difficulty trying to parse an XML content with Xpath. Xml includes namespace information. I have tried to create a NameSpaceContextImp (apache WS commons implementations of NameSpaceContext interface in jdk) to map the namaspace prefixes to URIs, however couldn't successfully queried the xml document. When I use online xpath testing tool at http://chris.photobooks.com/xml/default.htm, the xpath query I use comes up with my expected nodes/elements. So I am trying to figure out what it is that I am doing wrong. I am providing the xml document and the sample code snippet. I would appreciate any feedback. As a note, I have tried xpath queries both with and without the namespace prefixes.

NamespaceContextImpl namespaceContext = new NamespaceContextImpl();
namespaceContext.startPrefixMapping("wsp", "http://schemas.xmlsoap.org/ws/2002/12/policy");
namespaceContext.startPrefixMapping("L7p", "http://www.layer7tech.com/ws/policy");
String policyXml = "xml content that is pasted below"
InputSource inputSource = new InputSource(new StringReader(policyXml));
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xPath = xpathFactory.newXPath();
xPath.setNamespaceContext(namespaceContext);
XPathExpression xpathExpression = xPath.compile("/wsp:Policy/wsp:All");
String evaluation = xpathExpression.evaluate(inputSource);
if (evaluation.trim().length() > 0) {
    System.out.println(evaluation);
}


    <?xml version="1.0" encoding="UTF-8"?>
<wsp:Policy xmlns:L7p="http://www.layer7tech.com/ws/policy" xmlns:wsp="http://schemas.xmlsoap.org/ws/2002/12/policy">
    <wsp:All wsp:Usage="Required">
        <L7p:SetVariable>
            <L7p:AssertionComment assertionComment="included">
                <L7p:Properties mapValue="included">
                    <L7p:entry>
                        <L7p:key stringValue="RIGHT.COMMENT"/>
                        <L7p:value stringValue="Used to enable message logging, Null (allow MSGDEBUG Header to set level), 0 - default,1 - Medium,2 - Full"/>
                    </L7p:entry>
                </L7p:Properties>
            </L7p:AssertionComment>
            <L7p:Base64Expression stringValue=""/>
            <L7p:VariableToSet stringValue="LOCAL_POLICY_DEBUG_LEVEL"/>
        </L7p:SetVariable>
        <L7p:Include>
            <L7p:PolicyGuid stringValue="ec1f4166-4299-4e44-bf9d-c5c2a9f0c894"/>
        </L7p:Include>
        <L7p:SslAssertion>
            <L7p:Option optionValue="Optional"/>
        </L7p:SslAssertion>
        <wsp:OneOrMore L7p:Enabled="false" wsp:Usage="Required">
            <L7p:SpecificUser>
                <L7p:Enabled booleanValue="false"/>
                <L7p:IdentityProviderOid longValue="-2"/>
                <L7p:UserLogin stringValue="test"/>
                <L7p:UserName stringValue="test"/>
                <L7p:UserUid stringValue="58916874"/>
            </L7p:SpecificUser>
            <L7p:SpecificUser>
                <L7p:Enabled booleanValue="false"/>
                <L7p:IdentityProviderOid longValue="-2"/>
                <L7p:UserLogin stringValue="test"/>
                <L7p:UserName stringValue="test"/>
                <L7p:UserUid stringValue="58916873"/>
            </L7p:SpecificUser>
            <L7p:SpecificUser>
                <L7p:Enabled booleanValue="false"/>
                <L7p:IdentityProviderOid longValue="-2"/>
                <L7p:UserLogin stringValue="test"/>
                <L7p:UserName stringValue="test"/>
                <L7p:UserUid stringValue="58916876"/>
            </L7p:SpecificUser>
            <L7p:SpecificUser>
                <L7p:Enabled booleanValue="false"/>
                <L7p:IdentityProviderOid longValue="-2"/>
                <L7p:UserLogin stringValue="test"/>
                <L7p:UserName stringValue="test"/>
                <L7p:UserUid stringValue="58916875"/>
            </L7p:SpecificUser>
            <L7p:SpecificUser>
                <L7p:Enabled booleanValue="false"/>
                <L7p:IdentityProviderOid longValue="-2"/>
                <L7p:UserLogin stringValue="testengineering-user"/>
                <L7p:UserName stringValue="testengineering-user"/>
                <L7p:UserUid stringValue="48201728"/>
            </L7p:SpecificUser>
        </wsp:OneOrMore>
        <wsp:OneOrMore wsp:Usage="Required">
            <L7p:HttpRoutingAssertion>
                <L7p:ProtectedServiceUrl stringValue="http://localhost:13000/Services/Finance/v1"/>
                <L7p:RequestHeaderRules httpPassthroughRuleSet="included">
                    <L7p:Rules httpPassthroughRules="included">
                        <L7p:item httpPassthroughRule="included">
                            <L7p:Name stringValue="Cookie"/>
                        </L7p:item>
                        <L7p:item httpPassthroughRule="included">
                            <L7p:Name stringValue="SOAPAction"/>
                        </L7p:item>
                    </L7p:Rules>
                </L7p:RequestHeaderRules>
                <L7p:RequestParamRules httpPassthroughRuleSet="included">
                    <L7p:ForwardAll booleanValue="true"/>
                    <L7p:Rules httpPassthroughRules="included"/>
                </L7p:RequestParamRules>
                <L7p:ResponseHeaderRules httpPassthroughRuleSet="included">
                    <L7p:Rules httpPassthroughRules="included">
                        <L7p:item httpPassthroughRule="included">
                            <L7p:Name stringValue="Set-Cookie"/>
                        </L7p:item>
                    </L7p:Rules>
                </L7p:ResponseHeaderRules>
            </L7p:HttpRoutingAssertion>
            <L7p:Include>
                <L7p:PolicyGuid stringValue="b438384e-eeb0-45c5-8a7e-d30da78f07ee"/>
            </L7p:Include>
        </wsp:OneOrMore>
    </wsp:All>
</wsp:Policy>
John
  • 877
  • 4
  • 11
  • 19

2 Answers2

1

The only CDATA under the All element is whitespace, which you trim. If you want to get DOM elements, use the NODE or NODESET (NodeList) options.

String xml = "<foo><bar baz='hello' /></foo>";
InputSource src = new InputSource(new StringReader(xml));
XPathExpression expr = XPathFactory.newInstance().newXPath()
    .compile("/foo/bar");
Node node = (Node) expr.evaluate(src, XPathConstants.NODE);

Transformer trans = TransformerFactory.newInstance().newTransformer();
trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
trans.transform(new DOMSource(node), new StreamResult(System.out));
McDowell
  • 107,573
  • 31
  • 204
  • 267
  • Thanks. Your comment about CDATA got me working. While trying too many things, I also simplified my xpath query and was not looking for actual element/attribute that I was orginally looking for. I haven't tried your code snipped and don't really understand why I would need a transformer. – John Jun 05 '12 at 21:02
  • @John - The transformer is only for printing the XML to `System.out` in the demo code since `toString()` doesn't do much on a `Node` type - see [here](http://stackoverflow.com/questions/1219596). – McDowell Jun 06 '12 at 07:53
0

Calling evaluate() with one argument requests conversion of the result to a string, which is equivalent to taking the string value of the requested node: that is, the concatenation of the text node descendants of the selected element. Since all the descendant text nodes are whitespace, you will get nothing back.

For once, namespaces are not the issue.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164