[XSL-LIST Mailing List Archive Home]
[By Thread]
[By Date]
RE: [xsl] Xpath related to following-sibling and preceding-sibling
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 |