RE: [xsl] Grouping with keys

Subject: RE: [xsl] Grouping with keys
From: "G. Ken Holman" <gkholman@xxxxxxxxxxxxxxxxxxxx>
Date: Thu, 24 Oct 2013 15:56:40 -0400
At 2013-10-24 15:31 -0400, Rick Quatro wrote:
Thanks for reply. I can't really key on the <p> elements because there could
be different elements before the first <li> in a group.

Sure ... but you could then key on anything that isn't an <li>.


I want to key on the
first <li> in each group regardless of its immediate preceding sibling.

I would rather key on the last element before each first <li>, not on the <li> itself. That is where I think you are going too deep: when you find yourself in the nodes to be handled with special handling, it is too awkward to handle them specially. I try to stay away from the nodes and handle them "outside" of themselves. Or have I said that correctly? Back to the XSLT design approach of looking at things "top-down", I want to handle the <li> grouping at arm's length, not while I'm in the <li> being grouped. That is going too far.


Forgive me if I sound pedantic, but you said in your earlier note you really wanted to understand this.

Just keep thinking "top-down" and how it is easier to handle items from arm's length rather than from inside.

Also, I want to use template rules instead of pull processing.

That is a straightforward adaptation. In my solution you'll see that I'm using the push model and the special handling of grouping is done agnostic of the element (provided it isn't an li). In the grouping I add the inferred structure. The handling of everything else is done independent of the grouping logic.


I hope you find the version below helpful.

. . . . . . . . Ken


t:\ftemp>type rick.xml <body> <li>one</li> <li>two</li> <p>paragraph</p> <li>three</li> <li>four</li> <p>paragraph</p> <li>five</li> <li>six</li> </body> t:\ftemp>call xslt rick.xml rick.xsl <?xml version="1.0" encoding="utf-8"?> <body> <ol> <li>one</li> <li>two</li> </ol> <p>paragraph</p> <ol> <li>three</li> <li>four</li> </ol> <p>paragraph</p> <ol> <li>five</li> <li>six</li> </ol> </body> t:\ftemp>type rick.xsl <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">

<xsl:key name="li" match="li"
       use="generate-id((..|preceding-sibling::*[not(self::li)][1])[last()])"/>

<xsl:output indent="yes"/>

<!--this is a construct whose children need to be grouped in separate lists-->
<xsl:template match="body">
  <body>
    <xsl:apply-templates mode="group" select=".|*[not(self::li)]"/>
  </body>
</xsl:template>

<xsl:template mode="group" match="*">
  <xsl:apply-templates select="self::*[not(self::body)]"/>
  <xsl:if test="key('li',generate-id(.))">
    <ol>
      <xsl:apply-templates select="key('li',generate-id(.))"/>
    </ol>
  </xsl:if>
</xsl:template>

<!--the following template rules need no knowledge of grouping-->

<xsl:template match="p">
  <p><xsl:apply-templates/></p>
</xsl:template>

<xsl:template match="li">
  <li><xsl:apply-templates/></li>
</xsl:template>

</xsl:stylesheet>
t:\ftemp>rem Done!


-- Public XSLT, XSL-FO, UBL & code list classes: Melbourne, AU May 2014 | Contact us for world-wide XML consulting and instructor-led training | Free 5-hour lecture: http://www.CraneSoftwrights.com/links/udemy.htm | Crane Softwrights Ltd. http://www.CraneSoftwrights.com/s/ | G. Ken Holman mailto:gkholman@xxxxxxxxxxxxxxxxxxxx | Google+ profile: https://plus.google.com/116832879756988317389/about | Legal business disclaimers: http://www.CraneSoftwrights.com/legal |

Current Thread