Can an XSLT processor store empty CDATA sections?

I am processing an XML document (InstallAnywhere.iap_xml installer) before passing it to another tool (InstallAnywhere) to update some values. However, the XSLT transformation I am using appears to strip the CDATA sections (which appear to be significant to InstallAnywhere) from the document.

I am using Ant 1.7.0, JDK 1.6.0_16 and an id based stylesheet:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" encoding="UTF-8" cdata-section-elements="string" />
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

      

Basically, "string" nodes that look like this:

<string><![CDATA[]]></string>

      

processed in:

<string/>

      

From reading the XSLT FAQ, I can see that what is happening is legal with respect to the XSLT specification. Is there a way to prevent this and convince the XSLT processor to emit the CDATA section?

+2


source to share


3 answers


To do this, you need to add a special case for empty elements string

and use disable-output-escaping

. I don't have a copy of Ant to test, but the following pattern worked for me with libxml

xsltproc

, which shows the same behavior that you describe:

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

    <xsl:template match="string">
        <xsl:choose>
            <xsl:when test=". = ''">
                <string>
                    <xsl:text disable-output-escaping="yes"><![CDATA[]]></xsl:text>
                </string>
            </xsl:when>

            <xsl:otherwise>
                <xsl:copy-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

      

Input:



<input>
    <string><![CDATA[foo]]></string>
    <string><![CDATA[]]></string>
</input>

      

Output:

<input>
    <string><![CDATA[foo]]></string>
    <string><![CDATA[]]></string>
</input>

      

0


source


Found a solution:

<xsl:template match="string">
    <xsl:element name="string">
        <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text><xsl:value-of select="text()" disable-output-escaping="yes" /><xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
    </xsl:element>
</xsl:template>

      



I also removed the cdata-section-elements attribute from the <xsl: output> element.

Basically, since the CDATA sections are important for the next tool in the chain, I output them manually.

+1


source


After the XML parser has finished working with XML, there is no difference between <![CDATA[abc]]>

and abc

. The same is true for an empty line - <![CDATA[]]>

it permits nothing at all and is silently ignored. It has no representation in the XML model. In fact, there is no way to tell the difference with CDATA and regular strings, and neither has a representation in the XML model.

Unfortunately.

Now why do you need this? Perhaps there is another solution that can help you?

0


source







All Articles