xmlxsltxslt-1.0xslt-2.0cdata

how to add cdata to an xml file using xsl


I am trying to wrap CDATA for the elements in an xml file.

Another point i missed was, there are some elements with same names those need to be escaped from adding CDATA.

This is the source xml file:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<books>
    <jndi:binding name="books/cat/action/configs">
        <jndi:value type="java.lang.String">
            <urlConfig>
              <defaults catID="1983" subcatID="1987" method="get" onError="keep"/>
              <urlKey name="logo" altURL="def.com">
                <address>abc.com</address>
              </urlKey>
              <urlKey name="logo1" altURL="def.com">
                <address>abc.com</address>
              </urlKey>
            </urlConfig>
        </jndi:value>
    </jndi:binding>
    <jndi:binding name="books/cat/romance/configs">
        <jndi:value type="java.lang.String">
            <urlConfig>
              <defaults catID="1983" subcatID="1987" method="get" onError="keep"/>          
              <urlKey name="logo" altURL="def.com">
                <address>abc.com</address>
              </urlKey>          
              <urlKey name="logo1" altURL="def.com">
                <address>abc.com</address>
              </urlKey>  
            </urlConfig>
        </jndi:value>
    </jndi:binding>
<jndi:binding name="books/cat/thriller/configs">
    <jndi:value type="java.lang.String">
        abc.com
    </jndi:value>
</jndi:binding> 
<jndi:binding name="books/cat/classic/configs">
    <jndi:value type="java.lang.String">
        abc.com
    </jndi:value>
</jndi:binding>
</books>

I have tried to use the same trick that @Dimitre Novatchev has mentioned here at How to insert CDATA into XML text markup exported from Access 2003?. But some how that's not working for me.

This is the xsl file that i tried:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:jndi="urn:jboss:jndi-binding-service:1.0"  >
 <xsl:strip-space elements="*"/>
 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

Can some one suggest me how to add CDATA to an element and also need to add an additional line <?xml version="1.0" encoding="ISO-8859-1"?> at the beginning of CDATA.

Here is the expected out:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<books>
    <jndi:binding name="books/cat/action/configs">
        <jndi:value type="java.lang.String">
        <![CDATA[
            <?xml version="1.0" encoding="ISO-8859-1"?>
            <urlConfig>
              <defaults catID="1983" subcatID="1987" method="get" onError="keep"/>
              <urlKey name="logo" altURL="def.com">
                <address>abc.com</address>
              </urlKey>
              <urlKey name="logo1" altURL="def.com">
                <address>abc.com</address>
              </urlKey>
            </urlConfig>
        ]]> 
        </jndi:value>
    </jndi:binding>
    <jndi:binding name="books/cat/romance/configs">
        <jndi:value type="java.lang.String">
        <![CDATA[
            <?xml version="1.0" encoding="ISO-8859-1"?>
            <urlConfig>
              <defaults catID="1983" subcatID="1987" method="get" onError="keep"/>          
              <urlKey name="logo" altURL="def.com">
                <address>abc.com</address>
              </urlKey>          
              <urlKey name="logo1" altURL="def.com">
                <address>abc.com</address>
              </urlKey>  
            </urlConfig>
        ]]> 
        </jndi:value>
    </jndi:binding>
<jndi:binding name="books/cat/thriller/configs">
    <jndi:value type="java.lang.String">
        abc.com
    </jndi:value>
</jndi:binding> 
<jndi:binding name="books/cat/classic/configs">
    <jndi:value type="java.lang.String">
        abc.com
    </jndi:value>
</jndi:binding>
</books>

Solution

  • The problem is that you need to convert the XML that goes inside the CDATA sections into text. This XSLT should do the job:

    <xsl:stylesheet 
      version="1.0" 
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:jndi="urn:jboss:jndi-binding-service:1.0">
    
      <xsl:output method="xml" indent="yes" cdata-section-elements="jndi:value"/>
    
      <xsl:template match="jndi:value">
        <xsl:copy>
          <!-- Copy the attributes -->
          <xsl:apply-templates select="@*"/>
          <!-- Convert the contained nodes (elements and text) into text -->
          <xsl:variable name="subElementsText">
            <xsl:apply-templates select="node()" mode="asText"/>
          </xsl:variable>
          <!-- Output the XML directive and the converted nodes -->
          <xsl:value-of select="concat('&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;',$subElementsText)"/>
        </xsl:copy>
      </xsl:template>
    
      <!-- Copy text nodes as text -->
      <xsl:template match="text()" mode="asText">
        <xsl:copy/>
      </xsl:template>
    
      <!-- Copy elements as text -->
      <xsl:template match="*" mode="asText">
        <xsl:value-of select="concat('&lt;',name())"/>
        <xsl:for-each select="@*">
          <xsl:value-of select="concat(' ',name(),'=&quot;',.,'&quot;')"/>
        </xsl:for-each>
        <xsl:value-of select="'&gt;'"/>
        <xsl:apply-templates select="node()" mode="asText"/>
        <xsl:value-of select="concat('&lt;/',name(),'&gt;')"/>
      </xsl:template>
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    Basically it uses a couple of templates to match the XML elements that need to be converted to text and convert them 'manually'. The cdata-section-elements directive does the rest.

    When applied to

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <books xmlns:jndi="urn:jboss:jndi-binding-service:1.0">
      <jndi:binding name="books/cat/action/configs">
        <jndi:value type="java.lang.String">
          <urlConfig>
            <defaults catID="1983" subcatID="1987" method="get" onError="keep"/>
            <urlKey name="logo" altURL="def.com">
              <address>abc.com</address>
            </urlKey>
            <urlKey name="logo1" altURL="def.com">
              <address>abc.com</address>
            </urlKey>
          </urlConfig>
        </jndi:value>
      </jndi:binding>
      <jndi:binding name="books/cat/romance/configs">
        <jndi:value type="java.lang.String">
          <urlConfig>
            <defaults catID="1983" subcatID="1987" method="get" onError="keep"/>
            <urlKey name="logo" altURL="def.com">
              <address>abc.com</address>
            </urlKey>
            <urlKey name="logo1" altURL="def.com">
              <address>abc.com</address>
            </urlKey>
          </urlConfig>
        </jndi:value>
      </jndi:binding>
    </books>
    

    produces the expected result:

    <?xml version="1.0" encoding="utf-8"?>
    <books xmlns:jndi="urn:jboss:jndi-binding-service:1.0">
      <jndi:binding name="books/cat/action/configs">
        <jndi:value type="java.lang.String"><![CDATA[<?xml version="1.0" encoding="utf-8"?>
          <urlConfig>
            <defaults catID="1983" subcatID="1987" method="get" onError="keep"></defaults>
            <urlKey name="logo" altURL="def.com">
              <address>abc.com</address>
            </urlKey>
            <urlKey name="logo1" altURL="def.com">
              <address>abc.com</address>
            </urlKey>
          </urlConfig>
        ]]></jndi:value>
      </jndi:binding>
      <jndi:binding name="books/cat/romance/configs">
        <jndi:value type="java.lang.String"><![CDATA[<?xml version="1.0" encoding="utf-8"?>
          <urlConfig>
            <defaults catID="1983" subcatID="1987" method="get" onError="keep"></defaults>
            <urlKey name="logo" altURL="def.com">
              <address>abc.com</address>
            </urlKey>
            <urlKey name="logo1" altURL="def.com">
              <address>abc.com</address>
            </urlKey>
          </urlConfig>
        ]]></jndi:value>
      </jndi:binding>
    </book