1

I have to parse oprResult/@code from below XML using XPath. The XPath expression

//*[local-name()='oprResult']/@code

is working as expected, BUT I could not use name or local-name functions as '(' ')' are used as delimiter in my parsing function.

Is it possible to parse oprResult without local-name?

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <ChangeResponse xmlns="http://www.example.com" code="0" message="Success">
            <oprResult code="0" message="Success"/>
        </ChangeResponse>
    </soap:Body>
</soap:Envelope>
kjhughes
  • 106,133
  • 27
  • 181
  • 240
anurag
  • 82
  • 2
  • 10
  • 1
    You don't have to use predicates (expressions in square brackets) to select elements. Simply specify a path: `//oprResult/@code`. A proper solution would be to fix your "parsing function" to not use parentheses as delimiters. – predi Oct 13 '14 at 07:35
  • 5
    `local-name` is necessary when you're trying to ignore namespaces (http://stackoverflow.com/questions/4402310/how-to-ignore-namespace-when-selecting-xml-nodes-with-xpath). If that's the case here, use the correct namespace instead. – Joe Oct 13 '14 at 08:33
  • //oprResult/@code didn't worked in my case. parsing function change may affect whole system as there are a no of xpath mapped already for different results. There may be many side effects. Unfortunately there is no namespace given for so using namespace is also not possible in this case – anurag Oct 13 '14 at 09:35
  • 2
    What environment do you use XPath in? Java? There _is_ a namespace defined for `ChangeResponse`, just not with a prefix, since it is a default namespace. But the prefix is irrelevant - depending on the environment you could perhaps register that namespace before applying the XPath expression. – Mathias Müller Oct 13 '14 at 12:20
  • Oh, and in case I was not clear on this, what I meant was: Show more code, not just the path expression in isolation. – Mathias Müller Oct 13 '14 at 12:21

1 Answers1

3

Is it possible to parse oprResult without local-name?

Yes*

Not only is it possible to select an XML element without using local-name(), it is actually preferred.

One common reason you see example XPaths with constructs such as

//*[local-name()='oprResult']

is that namespace declarations are not an intrinsic part of XPath; namespace and namespace prefix declarations occur in the greater context of the system or language using an XPath library.

If you cannot make your system tolerate the parentheses of local-name(), if //oprResult/@code doesn't suite, or if you are simply interested in using namespaces properly rather than defeating them, figure out how to declare a namespace prefix, say ex: for the http://www.example.com namespace, and use the namespace prefix in the XPath. Read on for how...

You do not say what the language and/or library you're using for XPath, but here are a few examples to give a feel for what to look for...

XSLT:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
                xmlns:ex="http://www.example.com">
   ...

Python (LibXML):

my $xc = XML::LibXML::XPathContext->new($xhtml_doc);
$xc->registerNs('soap', 'http://schemas.xmlsoap.org/soap/envelope/');
$xc->registerNs('ex', 'http://www.example.com');

Javas (SAX):

NamespaceSupport support = new NamespaceSupport();
support.pushContext();
support.declarePrefix("soap", "http://schemas.xmlsoap.org/soap/envelope/");
support.declarePrefix("ex", "http://www.example.com");

Once you've declared namespace prefixes, your XPath can be:

/soap:Envelope/soap:Body/ex:ChangeResponse/oprResult/@code

* ...but the reason should not be to avoid parentheses because they "are used as delimiters in a parsing function." First of all, if an XPath parser is having trouble with embedded parens, get a new XPath parser; if a tool that uses an XPath library is preventing you from using parens, get a new tool (or investigate deeper to be sure the tool is not being used as well as it can be). Secondly, as @predi observed in the question comments, if there's only a single oprResult element and your response is small enough that you don't mind the inefficiency, in your case you can use an XPath without namespaces: //oprResult/@code

kjhughes
  • 106,133
  • 27
  • 181
  • 240