Yves,
While you can't restrict preceding-sibling to look only at members of
the current group, you might be able to get somewhere with either of
these approaches:
* The XPath 2.0 "intersect" operator can return those members common
to two sequences of nodes, so (preceding-sibling::node() intersect
current-group()) will return just those members of the current group
that are on the preceding-sibling axis relative to the context.
* If, rather than using grouping constructs to select from the nodes
in the source, you processed them into temporary trees, you could
construct those trees exactly the way you wanted, including nesting
elements in such a way that preceding-sibling would be useful. Such as:
<xsl:variable name="intermediate">
<xsl:for-each-group select="*" group-by=".">
<group>
<xsl:copy-of select="current-group()"/>
</group>
</xsl:for-each-group>
<xsl:variable>
<xsl:for-each select="$intermediate/group">
... inside each group element, members of the group appear as siblings ...
</xsl:for-each>
But I'm not sure either of these are actually necessary here. You
have only presented your problem in fragmentary form, so it's hard to
say; but to get the result you say you want, I'd do something much simpler:
<xsl:template match="/">
<xsl:for-each-group
select="root/*"
group-starting-with="A|B|C">
<xsl:apply-templates
select="current-group()[1]"
mode="groups_at_root_level">
<xsl:with-param name="this-group"
select="current-group()[position() gt 1]"/>
</xsl:apply-templates>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="B" mode="groups_at_root_level">
<xsl:param name="this-group" select="()"/>
<B_new>
<xsl:apply-templates select="$this-group"/>
</B_new>
</xsl:template>
<xsl:template match="sub">
<sub_new>
<xsl:apply-templates/>
</sub_new>
</xsl:template>
I hope that helps,
Wendell
At 01:18 PM 4/27/2007, you wrote:
Relying heavily on xsl:for-each-group in the context of rather
complicated transformations, I have run into this situation (and am
stuck there...): When specifying, in group-starting-with, the
pattern that may start some specific group, I would like to take
into account the number of items available for grouping.
More precisely, my group starting pattern must include a filter
using preceding-sibling which I do not want to "look beyond" the
current sequence of items to be grouped.
Showcasing this in a minimal example (more details below):
INPUT:
<root>
<A/>
<sub>a1</sub>
<B/>
<sub>b1</sub>
<sub>b2</sub>
<sub>b3</sub>
<C/>
<sub>c1</sub>
<sub>c2</sub>
</root>
OUTPUT:
<B_new>
<sub_new>b1</sub_new>
<sub_new>b2</sub_new>
<sub_new>b3</sub_new>
</B_new>
STYLESHEET:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<xsl:for-each-group
select="root/*"
group-starting-with="A|B|C">
<xsl:apply-templates
select="current-group()[1]"
mode="groups_at_root_level"/>
</xsl:for-each-group>
</xsl:template>
<!-- don't care for them now -->
<xsl:template match="A|C" mode="groups_at_root_level"/>
<xsl:template match="B" mode="groups_at_root_level">
<B_new>
<xsl:variable name="items_total" select="count(current-group())"/>
<xsl:for-each-group
select="current-group()"
group-starting-with="
B|
sub[not(
preceding-sibling::*[position() lt $items_total][A])]">
<xsl:apply-templates select="current-group()"/>
</xsl:for-each-group>
</B_new>
</xsl:template>
<xsl:template match="sub">
<sub_new>
<xsl:apply-templates/>
</sub_new>
</xsl:template>
<xsl:template match="*"/>
</xsl:stylesheet>
I would like to ask your opinion on the preceding-sibling line. If
it just read preceding-sibling::A, the output would of course miss
all "sub" instances. (Unfortunately, for reasons difficult to
explain here, I can't just drop the negated preceding-sibling filter
because I need it in some of my group starting patterns.)
Obviously, my above try at restricting the number of preceding
siblings to consider to those which are among the items to group is
rather limited: When xsl:for-each-group examines the very first
item, the first preceding sibling of that will already be outside of
the groupable items (while the last item will have many more
"acceptable" preceding siblings than the first). This makes me dream
of a kind of dynamic position counter returning the position of the
current item that xsl:for-each-group is trying to put into a group.
Is there such a thing?
Alternatively, how could I restrict sibling tests to the items which
are being grouped, inside the pattern of group-starting-with?
Yves
======================================================================
Wendell Piez
mailto:wapiez(_at_)mulberrytech(_dot_)com
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
======================================================================
--~------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--