Pairing Elements XSLT

Here should go questions about transforming XML with XSLT and FOP.
bay
Posts: 5
Joined: Tue Mar 04, 2008 5:07 am

Pairing Elements XSLT

Post by bay »

Hi,
I'm trying to write a transformation that takes repeating elements and places them in pairs and in order in the XML output. I want to convert this:

Code: Select all


<Root>
<heading>Chapter 1</heading>
<module>
<para>Para 1</para>
</module>
<module>
<para>Para 2</para>
</module>
<module>
<para>Para 3</para>
</module>
<module>
<para>Para 4</para>
</module>
<module>
<para>Para 5</para>
</module>
<heading>Chapter 2</heading>
<module>
<para>Para 6</para>
</module>
<module>
<para>Para 7</para>
</module>
<module>
<para>Para 8</para>
</module>
</Root>
into:

Code: Select all

<Root>
<heading>Chapter 1</heading>
<double_module>
<para>Para 1</para>
<para>Para 2</para>
</double_module>
<double_module>
<para>Para 3</para>
<para>Para 4</para>
</double_module>
<module>
<para>Para 5</para>
</module>
<heading>Chapter 2</heading>
<double_module>
<para>Para 6</para>
<para>Para 7</para>
</double_module>
<module>
<para>Para 8</para>
</module>
<heading>Chapter 3</heading>
</Root>
My current XSLT finds each element and pairs it with its following-sibling but because it processes each node I get a
<double_module><para>Para 1</para><para>Para 2</para></double_module> and a <double_module><para>Para 2</para><para>Para 3</para></double_module>

Code: Select all


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="Root">
<lesson>
<xsl:apply-templates/>
</lesson>
</xsl:template>
<xsl:template match="para">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="heading">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="module">
<xsl:choose>
<xsl:when test="following-sibling::*[1][self::module]"> <double_module>
<xsl:apply-templates/>
<xsl:apply-templates mode="in-module"
select="following-sibling::*[1][self::module]"/>
</double_module>
</xsl:when>
<xsl:otherwise>
<module>
<xsl:apply-templates/>
</module>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="module" mode="in-module">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
Any assistance is greatly appreciated.
Thanks,
Bay
jkmyoung
Posts: 89
Joined: Mon Mar 06, 2006 10:13 pm

Re: Pairing Elements XSLT

Post by jkmyoung »

Add this before your other module template:
<xsl:template match="module[position() mod 2 = 0]">
<xsl:apply-templates/>
</xsl:template>
bay
Posts: 5
Joined: Tue Mar 04, 2008 5:07 am

Re: Pairing Elements XSLT

Post by bay »

Thanks!

I assume you meant:

Code: Select all


<xsl:template match="module[position() mod 2 = 0]"/>
... which just about works.

The problem now is that module 6 (where position() mod 2 = 0)which follows a <chapter> should begin a <double_ module>, but instead is ignored by the above template.
bay
Posts: 5
Joined: Tue Mar 04, 2008 5:07 am

Re: Pairing Elements XSLT

Post by bay »

Perhaps recursion is required for this?
george
Site Admin
Posts: 2095
Joined: Thu Jan 09, 2003 2:58 pm

Re: Pairing Elements XSLT

Post by george »

Hi,

My approach will be with a positional processing. Match on the Root and apply templates on the first element. For heading and modules that do not have a pair just copy them and process the next sibling. The other modules will have a pair so when we match on one we copy the content of that and the content of the following module inside a double-module element.

Code: Select all


<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="Root">
<xsl:copy>
<xsl:apply-templates select="*[1]"/>
</xsl:copy>
</xsl:template>
<xsl:template
match="heading|module[following-sibling::*[1][self::heading] or
not(following-sibling::*)]">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::*[1]"/>
</xsl:template>

<xsl:template match="module">
<double-module>
<xsl:copy-of select="./*"/>
<xsl:copy-of select="following-sibling::*[1]/*"/>
</double-module>
<xsl:apply-templates select="following-sibling::*[2]"/>
</xsl:template>
</xsl:stylesheet>
Best Regards,
George
George Cristian Bina
bay
Posts: 5
Joined: Tue Mar 04, 2008 5:07 am

Re: Pairing Elements XSLT

Post by bay »

Worked great! Thanks very much.
Post Reply