Dono
Dono

Reputation: 53

Creating new XML nodes if sub node exists

I've been trying to achieve the following output using XSLT but have really been struggling. Thank you in advance for any assistance.

From

<par>
   <run>Line one<break/>
        Line two<break/>
   </run>

   <run>Another para of text<break/>
   </run>

   <run>3rd para but no break</run>    
</par>

To

 <document>
   <para>Line one</para>
   <para>Line two</para>
   <para>Another para of text</para>
   <para>3rd para but no break</para>
 </document>

Thank you,

Dono

Upvotes: 0

Views: 132

Answers (2)

ABach
ABach

Reputation: 3738

Here's a simple solution that is push-oriented and doesn't need <xsl:for-each>, <xsl:if>, or the self:: axis.

When this XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output omit-xml-declaration="yes" indent="yes" />
  <xsl:strip-space elements="*" />

  <xsl:template match="/*">
     <document>
       <xsl:apply-templates />  
     </document>
  </xsl:template>

  <xsl:template match="run/text()">
     <para>
       <xsl:value-of select="normalize-space()" />
     </para>
  </xsl:template>

</xsl:stylesheet>

...is applied to the provided XML:

<par>
   <run>Line one<break/>
        Line two<break/>
   </run>

   <run>Another para of text<break/>
   </run>

   <run>3rd para but no break</run>    
</par>

...the wanted result is produced:

<document>
  <para>Line one</para>
  <para>Line two</para>
  <para>Another para of text</para>
  <para>3rd para but no break</para>
</document>

Upvotes: 2

Alex Bishop
Alex Bishop

Reputation: 483

Assuming that your <run> elements are only ever going to contain text and <break/> elements, and that you want to normalise whitespace and exclude <para> elements that would only contain whitespace (suggested by your desired output), the following should work:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output indent="yes"/>

    <xsl:template match="par">
        <document>
            <xsl:apply-templates select="*"/>
        </document>
    </xsl:template>

    <xsl:template match="run">
        <xsl:for-each select="text()">
            <xsl:if test="normalize-space(self::text()) != ''">
                <para>
                    <xsl:value-of select="normalize-space(self::text())"/>
                 </para>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

Upvotes: 0

Related Questions