Re: dl/dt/dd matching

Subject: Re: dl/dt/dd matching
From: James Clark <jjc@xxxxxxxxxx>
Date: Thu, 14 Jan 1999 12:03:17 +0700
David Rosenborg wrote:
> 
> Another suggestion:
> 
> Allow the select patterns 'previous (MatchExpr)' and 'next (MatchExpr)'.
> 
> <xsl:template match="dl">
>   <table>
>     <xsl:for-each select="dt">
>       <tr>
>         <xsl:apply-templates/>
>         <xsl:apply-templates select="next (dd)"/>
>       </tr>
>     </xsl:for-each>
>   </table>
> <xsl:template>
> 
> <xsl:template match="dt|dd">
>   <td><xsl:apply-templates/></td>
> </xsl:template>
> 
> The previous and next patterns would select the nearest sibling
> of the current node that matches the match pattern.

Some harder cases are difficult to solve with just that.  For example,
the XML and XSL specs use productions marked up using a prod element
that has a content model like this:

<!ELEMENT prod (lhs, (rhs, (com|wfc|vc)*)+)>

The formatting that's needed is to put the lhs elements in one column,
the rhs elements in another, and the other elements in another, but no
more than one element per cell.  For example:

<prod>
<lhs>L1</lhs>
<rhs>R1</rhs>
<wfc>W1</wfc>
<rhs>R2</rhs>
<rhs>R3</rhs>
<vc>V2</vc>
<wfc>W2</wfc>
</prod>

would be formatted as:

<table>
<tr>
<td>L1</td>
<td>R1</td>
<td>W1</td>
</tr>
<tr>
<td></td>
<td>R2</td>
<td></td>
</tr>
<tr>
<td></td>
<td>R3</td>
<td>V2</td>
</tr>
<tr>
<td></td>
<td></td>
<td>W2</td>
</tr>
</table>

A variation on your suggestion can handle this:

- next-element() returns the next element sibling;

- next-element(MatchExpr) returns the next element sibling if it matches
MatchExpr (otherwise nothing)

Similarily for previous-element().

Given these, the above case can be handled as:

<xsl:template match="prod">
  <table>
    <!-- select elements that start a row -->
    <xsl:apply-templates select="lhs
                                 |rhs[not(previous-element(lhs))]
                                 |vc[not(previous-element(rhs))]
                                 |wfc[not(previous-element(rhs))]
                                 |com[not(previous-element(rhs))]"/>
  </table>
</xsl:template>

<xsl:template match="lhs">
<tr>
  <td><xsl:value-of select="."/></td>
  <xsl:for-each select="next-element()">
    <td><xsl:value-of select="."/></td>
    <td><xsl:value-of select="next-element(vc|wfc|com)"/></td>
   </xsl:for-each>
</tr>
</xsl:template>

<xsl:template match="rhs">
<tr>
  <td></td>
  <td><xsl:value-of select="."/></td>
  <td><xsl:value-of select="next-element(vc|wfc|com)"/></td>
</tr>
</xsl:template>

<xsl:template match="vc|wfc|com">
<tr>
<td></td>
<td></td>
<td><xsl:value-of select="."/></td>
</tr>
</xsl:template>

I just implemented this in XT.

James



 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread