0

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>
2
  • Can you say whether you are using XSLT 1.0 or XSLT 2.0 here? Thanks! Commented Jul 1, 2016 at 7:56
  • I am using XSLT 2.0. Commented Jul 1, 2016 at 8:48

3 Answers 3

1

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>
Sign up to request clarification or add additional context in comments.

Comments

0

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>

Comments

0

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.