xsl-list
[Top] [All Lists]

[xsl] Sibling axis: All of kind A up to first of kind B

2008-03-25 11:37:13
A simple text document: headers at two levels, and paragraphs.

<html>
  <h1>Eins</h1><p>Bla bla</p>
  <h2>Zwei</h2><p>Bla bla bla</p>
  <h2>Drei</h2><p>Bla bla blub</p>
  <h1>Vier</h1><p>Bla bla</p>
  <h2>Fuenf</h2><p>Bla bla bla</p>
  <h2>Sechs</h2><p>Bla bla</p>
</html>

I want to add something to this document. I want each h1 header
to be followed by a listing of its respective h2 headers, like
a summary. (You'll then know straight away what's in the
subsections.) This can be done using both sibling axes, first
forward, then backward.

<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="h1">
    <xsl:copy-of select="."/>
    <div class="toc"><!-- subheadings of current h1 -->
      <xsl:apply-templates select="following-sibling::h2[
        generate-id(preceding-sibling::h1[1]) =
        generate-id(current()) ]"/>
    </div>
  </xsl:template>
  <xsl:template match="@*|node()"><!-- copy template -->
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:transform>

This works fine. But is it efficient? Or is there a better way to
do this in XSL 1.0? If there were zillions of those headers, would
the processor then have to backtrack at each h2 in order to find
the first h1 in reverse document order and do the comparison? Or
are implementations required to be smarter than that so the user
doesn't have to care about these details?

How could I instruct the processor most efficiently to process all
h2 headers but only so long as there is no h1 header encountered
on the way, the way being the following-sibling axis?

The other day, "sibling recursion" was mentioned on this list.
Does the following qualify as sibling recursion - and is this
likely to be more efficient for large input?

<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="h1">
    <xsl:copy-of select="."/>
    <div class="h1toc"><!-- subheadings of current h1 -->
      <xsl:apply-templates mode="toc"
        select="(following-sibling::h1 | following-sibling::h2)[ 1 ]"/>
    </div>
  </xsl:template>
  <xsl:template match="h1" mode="toc"/><!-- stop on h1 -->
  <xsl:template match="h2" mode="toc"><!-- copy and continue -->
    <xsl:copy-of select="."/>
    <xsl:apply-templates mode="toc"
      select="(following-sibling::h1 | following-sibling::h2)[ 1 ]"/>
  </xsl:template>
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:transform>

Michael Ludwig

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--