tags:

views:

624

answers:

5

I have an application which extracts data from an XML file using XPath. If a node in that XML source file is missing I want to return the value "N/A" (much like the Oracle NVL function). The trick is that the application doesn't support XSLT; I'd like to do this using XPath and XPath alone.

Is that possible?

+1  A: 

Short answer: no. Such a function was considered and explicitly rejected for version 2 of the XPath spec (see the non-normative Illustrative User-written Functions section).

Hank Gay
A: 

It can be done with XPath 1.0. Say you have

<foo>
  <bar/>
</foo>

If you want to test if foo has a baz child,

substring("N/A", 4 * number(boolean(/foo/baz)))

will return "N/A" if the expression /foo/baz returns an empty node-set, otherwise it returns an empty string.

jelovirt
+1  A: 

It can be done but only if the return value when the node does exist is the string value of the node, not the node itself. The XPath

substring(concat("N/A", /foo/baz), 4 * number(boolean(/foo/baz)))

will return the string value of the baz element if it exists, otherwise the string "N/A".

To generalize the approach:

substring(concat($null-value, $node),
          (string-length($null-value) + 1) * number(boolean($node)))

where $null-value is the null value string and $node the expression to select the node. Note that if $node evaluates to a node-set that contains more than one node, the string value of the first node is used.

jelovirt
A: 

@jelovirt

So if I understand this correctly, we concatenate the default answer and the value of the node, and then take the correct subset of the resulting string by testing for the existence of the node to set the offset to either zero or the position right after my default string. That is the most perverse twisting of a language I've ever seen. (I love it!)

To clarify what you said, this approach works when the the node is missing, not when the node is empty. But by replacing "number(boolean($node))" with "string-length($node)" it will work on empty nodes instead.

JPLemme
A: 

For empty nodes, you need

boolean(string-length($node))

(You can omit the call to number() as the cast from boolean to number is implicit here.)

jelovirt