Re: [xsl] XSL, when elements don't exist

Subject: Re: [xsl] XSL, when elements don't exist
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Tue, 28 Oct 2003 15:24:55 -0500

At 02:37 PM 10/28/2003, you wrote:
I'm trying to process an XML document for which certain elements may or may
not exist.
How can I handle this?
<xsl:if test= "element exists"></xsl:if>
<xsl:if test= "element does not exist"></xsl:if>

The trick to this is knowing some of the details of how XPath works.

XPath has four data types. (XSLT 1.0 adds a fifth, the result-tree-fragment, which needn't concern us here.) They are:

node sets (sets of nodes in a source document)

In addition, XPath has rules about how to convert from any of these to the others. One of these rules, for converting a node set into a Boolean, is particularly handy: if the node set contains any nodes, it's true; if it doesn't, it's false.

Since a test attribute in a conditional expects a Boolean true or false, the trick for seeing whether a node exists is simply to retrieve it. If the set of nodes you get back contains any members, it passes the truth test; if it doesn't, it fails.

As I understand it, you need to do something special when nodes like these don't exist:

<property name="d" displayname="Defer Node Expansion" value="true" />
<property name="tr" displayname="Traverse DOM" value="true" />

...this would be (assuming your context node is the PropertyGroup):

<xsl:if test="not(child::property[@displayname='Defer Node Expansion']
               or child::property[@displayname='Traverse DOM'])">

using the Boolean 'or' operator (and the not() function), or

<xsl:if test="not(child::property[@displayname='Defer Node Expansion'] |
                  child::property[@displayname='Traverse DOM'])">

using the union operator '|', which combines two node sets.

If you apply the rule for converting node sets to Booleans in each case, you can see why they do the same thing here -- even though the 'or' operator is *not* the same as the '|' operator.

Incidentally, the casting rules referred to above make it generally superfluous in XSLT to write tests such as test="string-length(normalize-space($node) = 0", since you can always do things like test="not(normalize-space($node))" and get the same answer.

I hope this helps,

Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.      
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
  Mulberry Technologies: A Consultancy Specializing in SGML and XML

XSL-List info and archive:

Current Thread