Re: [xsl] Keeping an eye on processed nodes

Subject: Re: [xsl] Keeping an eye on processed nodes
From: "J.Pietschmann" <j3322ptm@xxxxxxxx>
Date: Wed, 15 Jan 2003 23:57:03 +0100
Gustaf Liljegren wrote:
I'm doing something really wrong here. I'm trying to process an index for a
book, and find myself in a situation where I need to keep an eye on which
nodes I have already processed. Since this is not possible in XSLT, I need
your help to find an alterntive solution. Part of the XML:

<?xml version="1.0" encoding="iso-8859-1"?>
<index>
  ...
  <entry page="34">A4 page size</entry>
  <entry page="37">absolute direction</entry>
  <entry page="172" context="absolute-position property">correcting
    content position with</entry>
  <entry page="91" context="absolute-position property">offsetting
    content with</entry>
  <entry page="139">alignment points</entry>
  ...
</index>

...
The problem occurs when several words are grouped.
Well, "grouping" is the key, of course. Search the XSL FAQ
for details.
I think you'll have to group by text content and context,
something like
 <xsl:key name="group" match="entry" use="concat(text(),'@',@context)"/>

 <xsl:template match="index">
   <xsl:for-each select="entry(generate-id()=
    generate-id(key('group',concat(text(),'@',@context))[1])">
    <xsl:sort select="text()"/>
    <xsl:value-of select="text()/>
    <xsl:if test="@context"/>
      <xsl:text>&#xA;  </xsl:text>
      <xsl:value-of select="@context/>
    </xsl:test>
    <xsl:for-each select="key('group',concat(text(),'@',@context))>
      <xsl:sort seletc="@page"/>
      <xsl:value-of select="@page"/>
      <xsl:text>,  </xsl:text>
    </xsl:for-each>
   </xsl:for-each>
 </xsl:template>

Processing runs of consecutive page numbers into the page range
notation can be a bit tricky unless the page numbers are already
sorted in the input, otherwise you'll probably have to use the
xx:node-set() extension to produce a sorted node set. Once you
have this, use a recursive template to detect runs. Another
possiblity could be really clever selection
 <xsl:for-each select="entry[
     previous-sibling::entry[1]/@page!=@page - 1"
     and following-sibling::entry[1]/@page=@page + 1
     and following-sibling::entry[2]/@page=@page + 2]">
   <!-- start of a run of more than two consecutive page numbers -->
   <xsl:variable name="startpage" select="@page"/>
   <xsl:value-of select="$startpage"/>
   <xsl:text>-</xsl:text>
   <xsl:value-of select="following-sibling::entry[
     @page=$startpage + count(previous-sibling::entry
       [@page &gt;= $startpage])][last()]/@page"/>
 </xsl:for-each>

Beware, untested. Look for boundary problems, off-by-one errors
etc. I also expect a recursive template solution to be more
efficient, probably noticably so if long runs of consecutive
page numbers occur often.

J.Pietschmann


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



Current Thread