[xsl] Test syntax, compare a string to a list and return true if there's an exact match

Subject: [xsl] Test syntax, compare a string to a list and return true if there's an exact match
From: Peter Desjardins <peter.desjardins.us@xxxxxxxxx>
Date: Thu, 12 Aug 2010 14:03:43 -0400
Hi. I've written a named template in XSLT 2.0 that I can call when I
need to find the generated IDs of following sibling elements that have
one of a specific set of "class" attributes. I've gotten my template
to work but there's a test in it that is very unwieldy. I need to
compare the class attribute value of a following sibling element to a
list of strings. The list might include four to ten possibilities and
the list will vary in different situations.

The use case here is that I'm handling XHTML elements with classes
such as "numberedlist." The template for those elements opens a
<listitem> element, then includes a <para> element for the XHTML
element value. But then, before it closes the <listitem> element, it
needs to reach ahead to certain following sibling elements such as
"numberedlist-cont" or "numberedlist-graphic" and apply templates for
them. When I have the list of generated IDs, I can handle each one
inside the <listitem>. I'm sure there are better ways to do this.

This is the test as I have it now. I've got an or condition for each
possibility.

    <xsl:when test="following-sibling::*[number($checkPosition)]/@class='MyTagClassTwo'
or following-sibling::*[number($checkPosition)]/@class='MyTagClassThree'">

This would not be so bad except that I'll have to redefine the
template in different situations. The list of interesting class
attribute values would be different in those situations (for example:
bulleted lists, sublists in the numbered lists). I'd like to make the
list of strings a parameter of the template.

I thought of using the contains($interestingClasses,
following-sibling::*[number($checkPosition)]/@class) function but I
want to make sure that "MyTagClass" is ignored even though
"MyTagClassTwo" is in the list.

Is there a function that will compare a string to a list of strings
and return true if one is an exact match? Is there a way I can write
this test differently so that I can test against a list of strings
from a parameter?

Thanks for your help! My processor is Saxon HE 9.2.1.1. Here's the
test in the context of the template:

<xsl:template name="checkFollowingSibling">
	<xsl:param name="followingSiblings"/><!-- We don't know of any
                                              the first time this template
                                              is called. -->
	<xsl:param name="checkPosition">1</xsl:param><!-- Start checking with
                                                      the first
following sibling
                                                      element. This will be
                                                      incremented with each
                                                      recursive call. -->
    <xsl:choose>

        <xsl:when
test="following-sibling::*[number($checkPosition)]/@class='MyTagClassTwo'
or following-sibling::*[number($checkPosition)]/@class='MyTagClassThree'">

            <!-- The test above will need to include another 'or' condition for
                 each possible class. I'd like to simplify this syntax. -->

            <xsl:call-template name="checkFollowingSibling"><!-- Since
the following

element matches one of
                                                                 the
interesting classes,

recursively call this
                                                                 template. -->
                <xsl:with-param name="followingSiblings">
                    <xsl:value-of select="$followingSiblings"/> <!--
Send whatever IDs we've

found so far. -->
                    <xsl:text>:</xsl:text>
                    <xsl:value-of
select="following-sibling::*[number($checkPosition)]/generate-id()"/>
                        <!-- Append the generated ID of the following
element. -->
                </xsl:with-param>
                <xsl:with-param name="checkPosition">
                    <xsl:value-of select="$checkPosition+1"/> <!--
Increment the following

sibling element position for
                                                                   the
next round. -->
                </xsl:with-param>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$followingSiblings"/> <!-- We've
come to the end of the

interesting following elements. Output
                                                             the list
so far (maybe nothing). -->
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Current Thread