[xsl] Unbounded element grouping/concatenation

Subject: [xsl] Unbounded element grouping/concatenation
From: "Gupta, Raman K [CI]" <raman.k.gupta@xxxxxxxxxxxxx>
Date: Mon, 8 Dec 2003 21:53:26 -0500
Hello,

I am trying to do something similar to the XSLT FAQ on Grouping,
question 17.  Concatenate two elements. Here is the original question
for your reference:

>   <record n="1" type="normal">
>     <foo> <x>... <y>...</y> ...</x> </foo>
>     <bar> <things> ... </things> </bar>
>   </record>
>   <record n="2" type="normal">
>     <foo> <x>... <y>...</y> ...</x> </foo>
>   </record>
>   <record n="3" type="continuation">
>     <bar> <things> ... </things> </bar>
>   </record>
>   <record n="4" type="normal">
>     <foo> <x>... <y>...</y> ...</x> </foo>
>     <bar> <things> ... </things> </bar>
>   </record>

In response to that post, Jeni Tennison gave a solution and wrote

> > Note that this method only works if there's only one continuation
> > for each normal record. If there might be more, then I'd use a 
> > key-based solution where you index each continuation record by its 
> > closest normal record and use that to identify which extra fields 
> > need to be added to the new record. If you need help with that, 
> > let us know.

Now, in my case I do have an unbounded number of continuation records for 
each normal record, and I need to concatenate all of them.

I followed Jeni's advice, and created a key as follows (this is my 
understanding of her directions, I could be wrong):

<xsl:key name="continuation-by-record"
  match="record[@type='continuation']"
  use="generate-id(preceding-sibling::record[@type='normal'][1])"/>
  
and then used that key to copy the appropriate continuation records for
each normal record:

<xsl:template match="records">
  <xsl:apply-templates select="record[@type = 'normal']" />
</xsl:template>

<xsl:template match="record">
  <record>
    <xsl:copy-of select="*" />
    <xsl:copy-of select="key('continuation-by-record', generate-id(.))/*"/>
  </record>
</xsl:template>

This works, except that it is *very* slow for anything more than a few
continuation records, presumably because the processer has to iterate,
for every continuation record, over all preceding sibling continuation 
records until it gets to a normal record (using xalan-j 2.4.0). For n
records,
this ends up being n factorial iterations.

I also tried a recursive template for the continuation record that only 
recurses if the following-sibling[1] is a continuation record also. 
This was *much* faster, but unfortunately for very large numbers 
of continuation records, the recursion causes a stack overflow.

Is there some other non-recursive efficient way of doing this? I am open
to multi-step transforms, etc.

Cheers,
Raman Gupta

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


Current Thread