Tests

1. Multiple test attributes
2. Expanding a pattern
3. Reduced match string in xslt2
4. Test if all elements are empty of text

1.

Multiple test attributes

Michael Kay


> I have some conditions where the action for a lot of them is the same.

> Is there any other way of grouping these than
> <xsl:choose>
>   <xsl:when test="@type='101' or @type='102' or @type='103' ...">
>     <xsl:do-something/>
>   </xsl:when>
>   <xsl:when test="@type='201' or @type='202' or @type='203' ...">
>     <xsl:do-something-else/>
>   </xsl:when>
> </xsl:choose>

> Is there a way doing something like:
> <xsl:choose>
>   <xsl:when test="@type='101'|'102'|'103'|'104'...">
> ..
> </xsl:choose>

With XSLT 2.0 you can write

<xsl:when test="@type = ('101', '102', '103')">

2.

Expanding a pattern

Michael Kay



> I have several references in my stylesheet to a pattern that 
> resembles:

> Node[@name='AA' or @name='BB']

> With time, I continuously need to update this pattern to 
> include newer attributes @name='CC', @name='DD' and so on.

This will become much easier in XSLT 2.0 with functions:

<xsl:function name="with-matching-name">
  <xsl:param name="node" as="element"/>
  <xsl:result as="xs:boolean" 
    select="$node/@name = ('AA', 'BB', 'CC')"/>
</xsl:function>

<xsl:...... select="Node[with-matching-name(.)]

3.

Reduced match string in xslt2

Michael Kay



 > I currently have
 >match="z:row[@Type='Matrix']/z:row[@MatrixOpt='1']
 >| z:row[@Type='Matrix']/z:row[@MatrixOpt='5']
 >| z:row[@Type='Matrix']/z:row[@MatrixOpt='6']"
 > How can I reduce the complexity?

With XSLT 2.0 you can write

match="z:row[@Type='Matrix']/z:row[@MatrixOpt=('1', '5', '6')]"

4.

Test if all elements are empty of text

Jeni Tennison



>> Given this, the fact that you're getting an error highlights for you
>> the fact that in XSLT 1.0 you're only testing the first of the rows
>> for content whereas you actually want to test if "all the cells are
>> empty" or, in other words, if any of the cells has content. For the
>> test to succeed when any of the $rows has content, you should use:
>> 
>>   count($rows) = 3 and $rows[normalize-space(.)]
>                           ^^^^^^^^^^^^^^^^^^^^^^^

The predicate works in XSLT 2.0 just as it does in XSLT 1.0 -- it filters the sequence of nodes held in the $rows variable to include only those for which the test "normalize-space(.)" is true. The test "normalize-space(.)" will be true for those nodes in $rows that have non-whitespace characters in their string values. The fact that the resulting sequence of nodes is used as an argument to the "and" operator means that the sequence is interpreted as a boolean value -- true if the sequence contains items and false otherwise. Therefore if there are any nodes left after the filtering (i.e. any nodes that have non-whitespace characters in their string values) then it will be true.

To make the boolean casts explicit, the above is the same as:

  count($rows) = 3 and boolean($rows[boolean(normalize-space(.))])

If you want to reinterpret that as a "some" expression, it's:

  count($rows) = 3 and
  some $r in $rows satisfies normalize-space($r)

or as a "for" expression:

  count($rows) = 3 and
  for $r in $rows return if (normalize-space($r)) then $r else ()

Since we know that there are three nodes in $rows, it's the same as:

  count($rows) = 3 and
  (normalize-space($rows[1]) or
   normalize-space($rows[2]) or
   normalize-space($rows[3]))

As far as what a processor would do, an optimised processor would most likely iterate over the nodes in $rows until it found one for which normalize-space(.) returned a non-empty string, and then return true for the sub-expression.