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>
 </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!=(_at_)page - 1"
and following-sibling::entry[1]/@page=(_at_)page + 1
and following-sibling::entry[2]/@page=(_at_)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
[(_at_)page >= $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