Reputation: 1020
I have a sample xsl like this,
<doc>
<p type="para">aaxx</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<context type="para">aaxx</context>
<p type="paraX">aaxx</p>
<s>jksjdl</s>
<p type="para">bbcc</p>
<p type="paraX">kkll</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<k>text</k>
<p type="para">bbcc</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
<t>text</t>
<p type="paraX">aa</p>
<p type="paraX">kddkll</p>
</doc>
My requirment is,
search for any <p type="para">
followed by any combination of p
with a type starting with paraX
and of <context type="para”>
and insert that content into a <section>
.
So, My expected output should look like,
<doc>
<section>
<p type="para">aaxx</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<context type="para">aaxx</context>
<p type="paraX">aaxx</p>
</section>
<s>jksjdl</s>
<section>
<p type="para">bbcc</p>
<p type="paraX">kkll</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
</section>
<k>text</k>
<section>
<p type="para">bbcc</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
</section>
<t>text</t>
<p type="paraX">aa</p>
<p type="paraX">kddkll</p>
</doc>
I've written following XSLT to do that,
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p[@type='para']"/>
<xsl:template match="p[@type='paraX']"/>
<xsl:template match="p[@type='para']">
<section>
<p type="para">
<xsl:apply-templates/>
</p>
<xsl:apply-templates select="following-sibling::*[1]" mode="box"/>
</section>
</xsl:template>
<xsl:template match="p" mode="box">
<p type="{@type}">
<xsl:apply-templates/>
</p>
<xsl:apply-templates select="following-sibling::p[1][@type='paraX'] | following-sibling::context[1][@type='para']" mode="box"/>
</xsl:template>
<xsl:template match="context" mode="box">
<context type="{@type}">
<xsl:apply-templates/>
</context>
<xsl:apply-templates select="following-sibling::p[1][@type='paraX'] | following-sibling::context[1][@type='para']" mode="box"/>
</xsl:template>
But it gives the following output,
<doc>
<section>
<p type="para">aaxx</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<context type="para">aaxx</context>
<p type="paraX">aaxx</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
<p type="paraX">aaxx</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
<context type="para">aaxx</context>
<p type="paraX">aaxx</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
</section>
<context type="para">aaxx</context>
<s>jksjdl</s>
<section>
<p type="para">bbcc</p>
<p type="paraX">kkll</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
</section>
<k>text</k>
<section>
<p type="para">bbcc</p>
<p type="paraX">aaxx</p>
<p type="paraX">aaxx</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
<p type="paraX">kkll</p>
<context type="para">aaxx</context>
<p type="paraX">kkll</p>
</section>
<context type="para">aaxx</context>
</doc>
Any idea how can I modify my templates to get the correct output?
Upvotes: 1
Views: 40
Reputation: 163496
You haven't specified the requirements clearly enough to be certain of getting the code right, but for the supplied input, the following would work:
<xsl:template match="doc">
<doc>
<xsl:for-each-group select="*"
group-starting-with="p[@type='para'] | *[not(self::p | self::context)]">
<xsl:choose>
<xsl:when test="self::p">
<section><xsl:copy-of select="current-group()"/></section>
<xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</doc>
</xsl:template>
I'm sure your approach using sibling recursion can be made to work, but personally I find positional grouping with for-each-group much clearer and easier to debug.
Upvotes: 2