This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Pattern: Processing Unwrapped Repeating Groups
- From: "W. Eliot Kimber" <eliot at isogen dot com>
- To: xsl list <xsl-list at lists dot mulberrytech dot com>
- Date: Wed, 30 Jan 2002 08:49:50 -0600
- Subject: [xsl] Pattern: Processing Unwrapped Repeating Groups
- Organization: ISOGEN
- Reply-to: xsl-list at lists dot mulberrytech dot com
In trying to solve a problem in the style sheet I'm currently developing
I stumbled on a pattern that I hadn't seen anywhere in my reading on XSL
processing--it's probably obvious to most but it took me a while to
figure it out so I thought I would share it.
The input data consists of what I call "unwrapped repeating groups, that
is, a content model like this:
<!ELEMENT z
(a, (b,c,d)+)
>
[I consider this style of content model to be bad form but you see it
quite a bit. My preference is to always have an intervening container
for any repeating OR or sequence groups, e.g.:
<!ELEMENT z
(a, w+)
>
<!ELEMEMT w
(b,d,d)
>
That is, avoid nested repeating groups. It generally makes things easier
for everybody, from authoring to processing.]
The intended presentation is as a table, e.g.:
.------------------.
| a | b1 | c1 | d1 |
| |----|----|----|
| | b2 | c2 | d2 |
'------------------'
The first and only "a" element starts the first row, but the 2nd..n "b"
elements start the 2nd through n rows.
The pattern I used to solve this problem is:
<xsl:template match="z">
<fo:table-cell starts-row="true">
<xsl:variable name="b-elems" select="b"/>
<xsl:attribute name="number-rows-spanned">
<xsl:value-of select="count($b-elems)"/>
</xsl:attribute>
<xsl:apply-templates select="a"/>
</fo:table-cell>
<xsl:for-each select="b">
<xsl:if test="position() > 1">
<fo:table-cell starts-row="true">
<fo:block/>
</fo:table-cell>
</xsl:if>
<fo:table-cell>
<xsl:apply-templates select="."/>
</fo:table-cell>
<fo:table-cell>
<xsl:apply-templates select="following::c[1]"/>
</fo:table-cell>
<fo:table-cell>
<xsl:apply-templates select="following::d[1]"/>
</fo:table-cell>
</xsl:for-each>
</xsl:template>
I first tried doing this by generating an enclosing fo:row but found it
too combersome because you have to process the first b,c,d tupple as a
special case. Fortunately, the ability to have cells start rows
simplifies the problem.
The key insight for me, as a novice XPath user, was the use of the
"following" axis to allow me to process the immediately following
siblings of each "b" element.
Cheers,
Eliot Kimber
ISOGEN International, LLC
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list