|
Subject: RE: [xsl] Xpath related to following-sibling and preceding-sibling From: "Michael Kay" <mhk@xxxxxxxxx> Date: Wed, 6 Aug 2003 09:26:14 +0100 |
This is a classical "positional grouping" problem. In XSLT 2.0 you can
do it using
<xsl:for-each-group group-adjacent="name()">
but in 1.0 it's more complex. There are two approaches. One is to treat
it as a value-based grouping problem, using Muenchian grouping with a
grouping key that is the generate-id() of the first Para in a group of
consecutive Para elements. The other way is to use apply-templates
recursively in the following-sibling direction.
<xsl:template match="BlockContent">
<xsl:apply-templates select="*[1]" mode="across"/>
</xsl:template>
<xsl:template match="*" mode="across">
<xsl:apply-templates select="."/>
<xsl:apply-templates select="following-sibling::*[1]" mode="across"/>
</xsl:template>
<xsl:template match="Para" mode="across">
<description>
<xsl:apply-templates select="."/>
<xsl:if test="following-sibling::*[1][self::Para]">
<xsl:apply-templates select="following-sibling::*[1]"
mode="para-across"/>
</xsl:if>
</description>
<xsl:apply-templates select="following-sibling::*[not(self::Para)][1]"
mode="across"/>
</xsl:template>
<xsl:template match="Para" mode="para-across">
<xsl:apply-templates select="."/>
<xsl:if test="following-sibling::*[1][self::Para]">
<xsl:apply-templates select="following-sibling::*[1]"
mode="para-across"/>
</xsl:if>
</xsl:template>
Not tested, and can be simplified.
Michael Kay
> -----Original Message-----
> From: owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> [mailto:owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx] On Behalf Of
> Teresa Rippeon
> Sent: 05 August 2003 19:42
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] Xpath related to following-sibling and
> preceding-sibling
>
>
>
> I have the following example XML data with the desired output:
>
> <Block id="block1">
> <BlockContent>
>
> <Para>This is para 1 in group 1</Para>
> <Para>This is para 2 in group 1</Para>
>
> <list><li>List item 1</li><li>List item 2</li></list>
>
> <Para>This is para 1 in group 2</Para>
> <Para>This is para 2 in group 2</Para>
> <Para>This is para 3 in group 2</Para>
> <Para>This is para 4 in group 2</Para>
>
> </BlockContent>
> </Block>
>
> With the following desired output:
>
> <description id="Block1_P1">
> <p>This is para 1 in group 1</p>
> <p>This is para 2 in group 1</p>
> </description>
>
> <list> .... </list>
>
> <description id="Block1_P4">
> <p>This is para 1 in group 2</p>
> <p>This is para 2 in group 2</p>
> <p>This is para 3 in group 2</p>
> <p>This is para 4 in group 2</p>
> </description>
>
> I have the following portion of the XSLT, which generates...
>
> <description id="Block1_P1">
> <p>This is para 1 in group 1</p>
> <p>This is para 2 in group 1</p>
> <p>This is para 1 in group 2</p>
> <p>This is para 2 in group 2</p>
> <p>This is para 3 in group 2</p>
> <p>This is para 4 in group 2</p></description>
> <list> .... </list>
>
> I know that I should have a check for a following-sibling
> that is not a Para, but as yet I have not been able to come
> up with the correct Xpath expression to complete this. Any
> suggestions? Thanks!
>
> <xsl:for-each
> select="//BlockContent/Para|//BlockContent/List|//BlockContent/Table">
>
> <!-- PARAs -->
> <xsl:if test="self::Para">
>
> <xsl:choose>
>
> <!-- When the preceding sibling was a para, then
> the description element has already been established
> and the para was appended into the
> description element in a previous for loop; don't want to write
> it out again -->
> <xsl:when test="preceding-sibling::Para">
> </xsl:when>
>
> <!-- Otherwise, establish the description
> element and put all consecutive paras within it as a chunk -->
> <xsl:otherwise>
> <xsl:call-template
> name="FormatXMLOutput"/>
>
> <xsl:element name="description">
>
> <xsl:attribute
> name="identifier">
> <xsl:value-of
> select="ancestor::Block[1]/@ID"/>
> <xsl:text>_P</xsl:text>
> <xsl:number count="Para"
> from="BlockContent" level="single"/>
> </xsl:attribute>
>
> <xsl:call-template
> name="FormatXMLOutput"/>
>
> <xsl:element name="p">
> <xsl:apply-templates/>
> </xsl:element>
>
> <!-- Now loop through all of the
> siblings of the Para so that all consecutive paras are
> "chunked" together in
> the description element.
> Note that the siblings are defined as on the same level so if
> there was a list
> between this para and the
> previous sibling para, then you don't want this in the same
> description
> element "chunk" -->
>
> <xsl:for-each
> select="following-sibling::Para">
> <xsl:element name="p">
>
> <xsl:apply-templates/>
> </xsl:element>
> </xsl:for-each>
>
>
> </xsl:element>
>
> </xsl:otherwise>
>
> </xsl:choose>
>
> </xsl:if>
>
> Etc. specifically dealing with lists, tables, etc.
>
> Thanks!
>
>
> XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
>
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
| Current Thread |
|---|
|
| <- Previous | Index | Next -> |
|---|---|---|
| [xsl] Xpath related to following-si, Teresa Rippeon | Thread | AW: AW: [xsl] Sorting Upper-Case fi, Markus Abt |
| Re: [xsl] comparing nodes by name, Jarkko Moilanen | Date | Re: AW: [xsl] Using key() from outs, David Carlisle |
| Month |