Re: [xsl] Trouble understanding the Test expression in xsl:if

Subject: Re: [xsl] Trouble understanding the Test expression in xsl:if
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Wed, 27 May 2009 16:59:40 -0400
Hi,

At 03:54 PM 5/27/2009, Ken wrote:
At 2009-05-27 14:28 -0500, Keith Gilbert wrote:
I'm having trouble getting my head around this:

My shortened XML data:

<category>
        <category_name>apples</category_name>
        <product>red delicious</product>
</category>
        <category_name>oranges</category_name>
        <product>sunkist</product>
</category>

My simplified XSLT:

<xsl:template match="category">
        <xsl:apply=templates/>
</xsl:template>

<xsl:template match="category_name">
        <xsl:if test="category_name = apples">
                <xsl:call-template name=apple_template/>
        </xsl:if>
</xsl:template>


For the life of me I can't figure out how to evaluate the value of "category_name" in the xsl:if line. I understand (I think) how to use xsl:value-of, but that doesn't seem to work inside the xsl:if. Any thoughts?

The content of an element is evaluated as a string from the concatenation of the descendent text nodes, and you incorrectly have:


<xsl:if test="category_name = apples">

... which tests the content of the child named "category_name" with the content of the child named "apples".

You want to compare the content to a string:

<xsl:if test="category_name = 'apples'">

Also, XPath evaluation is always relative to context, and "category_name" is a relative path expression, which starts at the current node, which is to say it starts at the element being matched. In XPath, "category_name" is short for "child::category_name" (just as "apples" is short for "child::apples", which conforms with Ken's point).


Since the element being matched here is always a "category_name", its "category_name" children will be examined, but if the sample data is correct, "category_name" never has children with the same name as itself. (This isn't impossible, but it isn't the case here.)

What you really want here is to compare the value of the current node itself, not its category_name children, to the string 'apples'. This would be:

<xsl:if test=". = 'apples'">

... which would be true if the value of the current node (whatever node is being matched) is string-equal to "apples".

A slightly more concise and versatile means to the same end would simply have:

<xsl:template match="category_name[. = 'apples']">
  <xsl:call-template name="apple_template"/>
</xsl:template>

... which would have the effect of calling the apple_template for any category_name element whose value is 'apples', while leaving other elements (including other category names) to match other templates.

Similarly, one might choose to match "category[category_name='apples']", and so forth.

Cheers,
Wendell



======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.                http://www.mulberrytech.com
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
======================================================================

Current Thread