xsl-list
[Top] [All Lists]

RE: Finding sequences of same element

2005-02-09 02:24:40
Search for "positional grouping" for solutions to this problem.

Assuming you want a pure XSLT 1.0 solution, rather than one that relies on
XSLT 2.0 for-each-group, or EXSLT extensions like set:leading(), a recursive
template is probably the simplest approach. In fact, it's sometimes easier
than using for-each-group. Remember that you can use apply-templates as well
as call-template for such problems. Try this:

<xsl:template match="A">
<xsl:copy>
  <xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>

<xsl:template match="A/*" priority="8">
<xsl:copy-of select="."/>
</xsl:template>

<xsl:template match="B[preceding-sibling::*[1][self::B]]" priority="15"/>

<xsl:template match="B" priority="10">
  <D>
    <xsl:apply-templates select="." mode="sequence"/>
  </D>
</xsl:template>

<xsl:template match="B" mode="sequence">
    <xsl:copy-of select="."/>
    <xsl:apply-templates select="following-sibling::*[1][self::B]"
mode="sequence"/>
</xsl:template>

The way to think about this is that you want to have a template rule for
every element in the result tree, and then you want to organize your
apply-templates to select the nodes in the input tree that will trigger
creation of a node in the result tree.

Michael Kay
http://www.saxonica.com/



-----Original Message-----
From: Simon Kissane [mailto:skissane(_at_)gmail(_dot_)com] 
Sent: 09 February 2005 07:59
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: [xsl] Finding sequences of same element

Hi

Suppose I have an input document:
<A><B X="1"/><B X="2"/><B X="3"/><C X="4"/><B X="5"/><B 
X="6"/><B X="7"/></A>

Now, suppose I wish to group together consecutive B elements, giving a
result document like this:
<A><D><B X="1"/><B X="2"/><B X="3"/></D><C X="4"/><D><B X="5"/><B
X="6"/><B X="7"/></D></A>

How can I do this? (I would prefer not to use recursive templates, but
rather for-each, if that is at all possible...)

I think I can find the initial element of these sequences, like so:
  B[not(preceding-sibling::*) or 
preceding-sibling::*[0][not(self::B)]]
This, I think, should select all B for which there are either no
preceeding sibling elements, or for which the immediately preceeding
sibling element is not a B element. Thus, in the above example, it
would pick B[(_at_)X=1] and B[(_at_)X=5](_dot_)

But, given each initial sequence element, how can I find the remaining
nodes in the sequence?  With the initial sequence element as the
context node, I could do:
    .|following-sibling::B
But that will also pick up B[(_at_)X=5] and B[(_at_)X=6] when the 
context node is B[(_at_)X=1](_dot_)

Is there a predicate test I could use on following-sibling::B to
restrict it only to the current sequence of B elements?

Thanks

Simon Kissane

--~------------------------------------------------------------------
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>
--~--



--~------------------------------------------------------------------
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>
--~--



<Prev in Thread] Current Thread [Next in Thread>