[xsl] XSLT 2.0 Grouping in XSLT 1.0 (was TEI > XML)

Subject: [xsl] XSLT 2.0 Grouping in XSLT 1.0 (was TEI > XML)
From: Daniel O'Donnell <daniel.odonnell@xxxxxxxx>
Date: Wed, 13 Apr 2005 00:05:01 -0600
Thanks to Jim and Mark for the suggestions for solving my problem... unfortunately, neither produce valid XHTML: the intervening bits of paragraph are still untagged.

That is to say, for the valid TEI/XML input:

<p>Text
 <quote>
  <p>quotation text</p>
 </quote>
 end text.</p>

The XHTML output (invalid) is

<p>text
 <blockquote>
  <p>quotation text</p>
 </blockquote>
 end text.</p>

not (valid):

 <p>text</p>
  <blockquote>
   <p>quotation text</p>
  </blockquote>
 <p>end text</p>


In the meantime, I've done a bit more research, and have discovered the solution in XSLT 2.0 (it's a canonical example): <http://www.w3.org/TR/xslt20/#d5e20377> "Grouping Alternating Sequences of Elements".


So to refine my question:

Is there a way of reproducing the results one gets in XSLT 2.0 (using the various grouping elements and attributes) in XSLT 1.0 (where these commands are not available).

Here is the example, desired output, and xslt 2.0 from the w3c:

Source XML document:

<p>Do <em>not</em>:
    <ul>
    <li>talk,</li>
    <li>eat, or</li>
    <li>use your mobile telephone</li>
    </ul>
    while you are in the cinema.</p>

Desired output:

<p>Do <em>not</em>:*</p>*
    <ul>
    <li>talk,</li>
    <li>eat, or</li>
    <li>use your mobile telephone</li>
    </ul>
    *<p>*while you are in the cinema.</p>

Solution:

This requires creating a p element around the maximal sequence of sibling nodes that does not include a ul or ol element.

This can be done by using group-adjacent, with a grouping key that is true if the element is a ul or ol element, and false otherwise:

<xsl:template match="p">
<xsl:for-each-group select="node()" group-adjacent="self::ul or self::ol">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:copy-of select="current-group()"/> </xsl:when>
<xsl:otherwise>
<p>
<xsl:copy-of select="current-group()"/>
</p>
</xsl:otherwise> </xsl:choose>
</xsl:for-each-group>
</xsl:template>



Adapted to the specific circumstance at hand, and applied to a test file (http://people.uleth.ca/~caedmon/lorem.xml), the following XSLT 2.0 produces valid results (http://people.uleth.ca/~caedmon/lorem.htm):


<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                version="2.0">

<xsl:output method="xml"/>

  <xsl:variable name="newline">
    <xsl:text>
    </xsl:text>
  </xsl:variable>

  <xsl:template match="/">
    <html>
      <head>
        <title>Quotes test</title>
      </head>
      <body>
        <xsl:apply-templates select="//body"/>
      </body>
    </html>
  </xsl:template>

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

<xsl:template match="teiHeader//*"/>

  <xsl:template match="quote[p]">
    <blockquote>
      <xsl:apply-templates/>
    </blockquote><xsl:value-of select="$newline"/>
  </xsl:template>

  <xsl:template match="table">
    <table><xsl:value-of select="$newline"/>
      <xsl:apply-templates/>
    </table><xsl:value-of select="$newline"/>
  </xsl:template>

  <xsl:template match="row">
    <tr><xsl:value-of select="$newline"/>
      <xsl:apply-templates/><xsl:value-of select="$newline"/>
    </tr><xsl:value-of select="$newline"/>
  </xsl:template>

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

  <xsl:template match="list">
    <xsl:choose>
      <xsl:when test="@rend='ordered'">
        <ol><xsl:value-of select="$newline"/>
          <xsl:apply-templates/>
        </ol><xsl:value-of select="$newline"/>
      </xsl:when>
      <xsl:otherwise>
        <ul><xsl:value-of select="$newline"/>
          <xsl:apply-templates/>
        </ul><xsl:value-of select="$newline"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="item">
    <li>
      <xsl:apply-templates/>
    </li><xsl:value-of select="$newline"/>
  </xsl:template>

  <xsl:template match="p">
    <xsl:for-each-group select="node()"
      group-adjacent="self::quote[p] or self::table or self::list">
      <xsl:choose>
        <xsl:when test="current-grouping-key()">
          <xsl:apply-templates select="current-group()"/>
        </xsl:when>
        <xsl:otherwise>
          <p>
            <xsl:copy-of select="current-group()"/>
          </p>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each-group>
  </xsl:template>

</xsl:stylesheet>


So the question is, how (can?) can this be done in XSLT 1.0?


Thanks again.
-dan

--
Daniel Paul O'Donnell, PhD
Associate Professor of English
University of Lethbridge
Lethbridge AB T1K 3M4
Tel. (403) 329-2377
Fax. (403) 382-7191
E-mail <daniel.odonnell@xxxxxxxx>
Home Page <http://people.uleth.ca/~daniel.odonnell/>
The Digital Medievalist Project: <http://www.digitalmedievalist.org/>

Current Thread