Reputation: 13
I want to wrap <text>
in separate <p>
having @align attribute. For more clarification please see the below example.
Source
<p>
<text>Check</text>
<text>Check2</text>
<text align="center">Final</text>
<text align="right">Final Check</text>
</p>
XSLT Code:
<xsl:template match="p">
<xsl:choose>
<xsl:when test="child::text/@align">
<xsl:element name="p">
<xsl:attribute name="align">
<xsl:value-of select="child::text/@align"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:template>
My Output
<p align="center right">
<text>Check</text>
<text>Check2</text>
<text>Final</text>
<text>Final Check</text>
</p>
Expected Output
<p>
<text>Check</text>
<text>Check2</text>
</p>
<p align="center">
<text>Final</text>
</p>
<p align="right">
<text>Final Check</text>
</p>
Upvotes: 0
Views: 149
Reputation: 116972
I would suggest you do it this way:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p">
<xsl:for-each-group select="text" group-adjacent="string(@align)">
<p>
<xsl:if test="current-grouping-key()">
<xsl:attribute name="align" select="current-grouping-key()" />
</xsl:if>
<xsl:apply-templates select="current-group()" />
</p>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="text/@align"/>
</xsl:stylesheet>
To understand the difference between this and the other suggestions, use this as the test input:
<p>
<text>Check</text>
<text>Check2</text>
<text align="center">Check3</text>
<text align="center">Check4</text>
<text align="right">Check5</text>
<text>Check6</text>
</p>
Upvotes: 0
Reputation: 70598
As you are using XSLT 2.0, you can make use of xsl:for-each-group
to group together text
elements with an align
attribute, and those without, and take the appropriate action in each case.
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p">
<xsl:for-each-group select="text" group-adjacent="boolean(@align)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:for-each select="current-group()">
<p align="{./@align}">
<xsl:apply-templates select="." />
</p>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<p>
<xsl:apply-templates select="current-group()" />
</p>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="text/@align" />
</xsl:stylesheet>
Upvotes: 1
Reputation: 819
Here is a simple solution that does exactly that.
<xsl:template match="p">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text[@align='center']">
<xsl:element name="p">
<xsl:attribute name="align">
<xsl:value-of select="'center'"/>
</xsl:attribute>
<xsl:element name="text">
<xsl:value-of select="."/>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="text[@align='right']">
<xsl:element name="p">
<xsl:attribute name="align">
<xsl:value-of select="'right'"/>
</xsl:attribute>
<xsl:element name="text">
<xsl:value-of select="."/>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="text">
<xsl:element name="p">
<xsl:element name="text">
<xsl:value-of select="."/>
</xsl:element>
</xsl:element>
</xsl:template>
Upvotes: 0