2

I have an xml string such as this:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <ExecuteResponse xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services">
      <ExecuteResult i:type="a:RetrieveEntityResponse" xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <a:ResponseName>RetrieveEntity</a:ResponseName>
        <a:Results xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
          <a:KeyValuePairOfstringanyType>
            <b:key>Some Value</b:key>
          </a:KeyValuePairOfstringanyType>
        </a:Results>
      </ExecuteResult>
    </ExecuteResponse>
  </s:Body>
</s:Envelope>

I'm trying to do something along the lines of:

var resolver = xmlDoc.createNSResolver(xmlDoc.documentElement);
return new XPathEvaluator().evaluate("//b:key", xmlDoc.documentElement, resolver, XPathResult.ANY_TYPE, null);

The key node is not being found, and the reason is when I call

resolver.lookupNamespaceURI("b")

directly, it returns null. However, it does return something when I do

resolver.lookupNamespaceURI("s")

so my best guess is the createNSResolver method only looks for namespaces in the root node of the xml document that is passed in. Is there any way to make it find all of the namespaces that are defined in the xml, or some other way to build a list of all of the namespaces that exist in the document?

Thanks!

1 Answer 1

3

Well setting up consistent namespace resolving based on all namespace declarations in the XML document is not possible in the general case as you could have e.g.

<root xmlns="http://example.com/n1">
  <foo xmlns="http://example.com/n2">
   <p1:bar xmlns:p1="http://example.com/n1">
    <p2:baz xmlns:p2="http://example.com/n1">...</p2:baz>
   </p1:bar>
  </foo>
</root>

where the same namespace is used with different prefixes and of course you could have samples as e.g.

<p:foo xmlns:p="http://example.com/n1">
  <p:bar xmlns:p="http://example.com/n2">...</p:bar>
</p:foo>

where the same prefix is bound to different namespace URIs on different elements.

So basically you need to know the namespace URI of the element node you are looking for, then you can set up a namespace resolver with any prefix your code can choose e.g.

return xmlDoc.evaluate("//pf:key", xmlDoc, function(prefix) { if (prefix === 'pf' return 'http://schemas.datacontract.org/2004/07/System.Collections.Generic'; else return null; }, XPathResult.ANY_TYPE, null);

On the other hand with that simple path I would not use XPath and evaluate at all but rather go for return xmlDoc.getElementsByTagNameNS('http://schemas.datacontract.org/2004/07/System.Collections.Generic', 'b');.

As for finding namespace declarations in a DOM tree to build up a namespace resolver yourself based on prefixes, XPath can give some assistance itself by looking at the namespace axis e.g. //namespace::* but inside the browser Mozilla/Firefox never considered it necessary to support the namespace axis. Then there are some DOM Level 3 methods http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespacePrefix and http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI so you could write your own code walking the DOM tree and collecting namespace declarations but that does not help in the general case to solve the problems outlined in the two example samples I posted above.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.