Re: [xsl] xslt 2. index-of, nodes

Subject: Re: [xsl] xslt 2. index-of, nodes
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Fri, 4 Jul 2003 10:30:24 +0100
Hi Dave,

> Below. small enough xml, full stylesheet.
> I couldn't shrink the stylesheet.
> Worked round the concat problem using string-join
> (what funny syntax!)

Ahh. Your stylesheet shows both why your grouping isn't working and
why concat() wasn't working. Remember my suggestion was to use:

  <xsl:for-each-group select="loc"
                      group-by="concat(@hl, '+', @side, '+', @pos)">
    ...
  </xsl:for-each-group>

This says "select the <loc> elements (these are the things that I want
to group) and group them by a combination of their hl, side and pos
attributes".

Compare this with what you have in your stylesheet:

  <xsl:for-each-group select="rec[mu/loc]"
    group-by="string-join((mu/loc/@hl,mu/loc/@side,mu/loc/@loc), '+')">
    ...
  </xsl:for-each-group>

This says "select the <rec> elements (that have <loc> grandchildren
under <mu> children) and group them by a concatenation of all their
<loc> grandchildren's hl attributes, all their <loc> grandchildren's
side attributes and all their <loc> grandchildren's loc attributes)".

So in your stylesheet, you're grouping the <rec> elements rather than
the <loc> elements. It shouldn't be surprising that since there's only
one <rec> element in your XML (from the looks of it), you only get one
group!

Try the following instead:

  <xsl:for-each-group select="rec/mu/loc"
                      group-by="concat(@hl, '+', @side, '+', @loc)">
    ...
  </xsl:for-each-group>

Note that you'll have to change the content of the inner
<xsl:for-each> to deal with the fact that the group will now contain
<loc> elements rather than <rec> elements.

The reason that concat() didn't work is that you were presumably
doing something like:

    concat(mu/loc/@hl, '+', mu/loc/@side, '+', mu/loc/@loc)

In this function call, the first, third and last arguments all select
sequences containing multiple nodes -- the <rec> elements has 9 <loc>
grandchildren, after all. The concat() function expects its arguments
to either be empty sequences ('empty node-sets' in XPath 1.0
terminology) or singleton sequences (single values or node-sets
containing a single node in XPath 1.0 terminology). When you got the
error:

> Error at xsl:for-each-group on line 54 of file:/C:/sgml/files/mu2.xsl:
>   A sequence of more than one item is not allowed here

it was because the arguments to the concat() function were, in fact,
sequences containing more than one item.

A concat() call like the one I suggested:

  concat(@hl, '+', @side, '+', @loc)

is fine because the paths @hl, @side and @loc cannot select more than
one node because no two attributes on an element are named the same.

(Note that in XPath 1.0, the processor would just silently select the
first of the nodes in the node sets passed as arguments to concat().
The fact that Saxon gave you an error was helpful here -- it should
have alerted you to the fact that you weren't doing what you thought
you were doing.)

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread