Reputation: 191
I am trying to convert a cals table to a series of lists and I am struggling with grouping.
The table consists of a couple of heading rows (thead/row), and a bunch of body rows (tbody/row). There are 2 types of body row: a) a standard data row, and b) a straddle heading row which 'break up' the table visually delineating each section.
I want to create a new list for each section and so am using
<xsl:for-each-group group-starting-with="row/entry/hd4" select="table/tgroup/tbody/row">
I have tried various options in the group-starting-with attribute including
entry/@nameend
entry[@nameend]
entry/hd4
entry[hd4]
From my background reading on this, I note that the value should be a pattern, and not a condition, so I'm guessing the predicates are wrong.
<anch fac="yes">
<p/>
<calstable>
<table frame="none">
<tgroup cols="4" colsep="0" rowsep="0">
<colspec colname="1" colnum="1" colwidth="39pt" align="center"/>
<colspec colname="2" colnum="2" colwidth="39pt" align="center"/>
<colspec colname="3" colnum="3" colwidth="45pt" align="center"/>
<colspec colname="4" colnum="4" colwidth="33pt" align="center"/>
<thead>
<row valign="bottom">
<entry align="center">Anchorage</entry>
<entry align="center">Lat.</entry>
<entry align="center">Long.</entry>
<entry align="center">Draft</entry>
</row>
<row valign="bottom">
<entry align="center">No.</entry>
<entry align="center">(S)</entry>
<entry align="center">(E)</entry>
<entry align="center">(m.)</entry>
<entry> </entry>
</row>
</thead>
<tbody>
<row>
<entry align="left" namest="1" nameend="4">
<hd4>Outer</hd4>
</entry>
</row>
<row>
<entry>O1</entry>
<entry>17° 57.0′</entry>
<entry>122° 04.0′</entry>
<entry>9.5</entry>
</row>
<row>
<entry>O2</entry>
<entry>17° 56.0′</entry>
<entry>122° 04.0′</entry>
<entry>9.5</entry>
</row>
<row>
<entry>O3</entry>
<entry>17° 55.0′</entry>
<entry>122° 04.0′</entry>
<entry>7.0</entry>
</row>
<row>
<entry align="left" namest="1" nameend="4">
<hd4>Gantheaume Bay</hd4>
</entry>
</row>
<row>
<entry>G1</entry>
<entry>17° 56.5′</entry>
<entry>122° 10.0′</entry>
<entry>8.0</entry>
</row>
<row>
<entry>G2</entry>
<entry>17° 55.0′</entry>
<entry>122° 10.0′</entry>
<entry>8.0</entry>
</row>
<row>
<entry>G2</entry>
<entry>17° 56.5′</entry>
<entry>122° 09.5′</entry>
<entry>8.0</entry>
</row>
</tbody>
</tgroup>
</table>
</calstable>
</anch>
and the xslt as follows
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0"
>
<xsl:output indent="yes" method="xml" standalone="yes"/>
<xsl:template match="/">
<anch>
<xsl:apply-templates select="anch/calstable" mode="cals-to-list"/>
</anch>
</xsl:template>
<xsl:template match="calstable[//thead[count(row) = 2]]" mode="cals-to-list">
<xsl:for-each-group group-starting-with="row/entry/hd4" select="table/tgroup/tbody/row">
<list>
<xsl:apply-templates select="current-group()" mode="cals-to-list"/>
</list>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="tbody/row[entry[@nameend]]" mode="cals-to-list">
<xsl:variable name="lhtype">
<xsl:choose>
<xsl:when test="entry/hd2">2</xsl:when>
<xsl:when test="entry/hd3">3</xsl:when>
<xsl:when test="entry/hd4">4</xsl:when>
<xsl:otherwise>2</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<lh lhtype="{$lhtype}">
<xsl:apply-templates select="entry[@nameend]" mode="cals-to-list"/>
</lh>
</xsl:template>
<xsl:template match="tbody/row[not(entry[@nameend])]" mode="cals-to-list">
<li>
<xsl:apply-templates select="entry" mode="cals-to-list"/>
</li>
</xsl:template>
<xsl:template match="row/entry[@nameend]" mode="cals-to-list">
<xsl:value-of select="*/text()"/>
</xsl:template>
<xsl:template match="row/entry[not(@nameend)]" mode="cals-to-list">
<xsl:variable name="pos" select="position()"/>
<xsl:variable name="thead-rows" select="count(ancestor::*[local-name()='tgroup']/thead/row)"/>
<xsl:variable name="top-line" select="normalize-space(ancestor::*[local-name()='tgroup']/thead/row[position() != $thead-rows]/entry[$pos]/text())"/>
<xsl:variable name="bot-line" select="normalize-space(ancestor::*[local-name()='tgroup']/thead/row[$thead-rows]/entry[$pos]/text())"/>
<xsl:variable name="unit" select="normalize-space(substring-before(substring-after($bot-line,'('),')'))"/>
<xsl:value-of select="$top-line"/><xsl:text> </xsl:text><xsl:value-of select="."/><xsl:text> </xsl:text><xsl:value-of select="$unit"/><xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
This is what I get
<anch xmlns:xs="http://www.w3.org/2001/XMLSchema">
<list>
<lh lhtype="4">Outer</lh>
<li>Anchorage O1 Lat. 17° 57.0′ S Long. 122° 04.0′ E Draft 9.5 m. </li>
<li>Anchorage O2 Lat. 17° 56.0′ S Long. 122° 04.0′ E Draft 9.5 m. </li>
<li>Anchorage O3 Lat. 17° 55.0′ S Long. 122° 04.0′ E Draft 7.0 m. </li>
<lh lhtype="4">Gantheaume Bay</lh>
<li>Anchorage G1 Lat. 17° 56.5′ S Long. 122° 10.0′ E Draft 8.0 m. </li>
<li>Anchorage G2 Lat. 17° 55.0′ S Long. 122° 10.0′ E Draft 8.0 m. </li>
<li>Anchorage G2 Lat. 17° 56.5′ S Long. 122° 09.5′ E Draft 8.0 m. </li>
</list>
</anch>
But I would expect the list to break and restart a new list just before the Gantheaume Bay entry.
Can someone explain where I've gone wrong and what the correct pattern should be?
TIA
Upvotes: 0
Views: 139
Reputation: 70648
You are selecting row
elements with the xsl:for-each-group
and so the group-starting-with
must also be a row
element (representing the first one each in group).
Change your xsl:for-each-group
to this...
<xsl:for-each-group group-starting-with="row[entry/hd4]" select="table/tgroup/tbody/row">
Upvotes: 2