XSLT 使用的 XPath 数据模型不允许区分任何 CDATA 部分——其中任何部分都被表示为文本节点的(部分)。因此,CDATA 保存不能完全使用 XSLT 或 XPath 来实现。它可以通过基于 DOM 的方法来实现。
如果在转换的输出中,具有特定名称的元素的文本节点需要 CDATA 部分,而其他元素则不需要,那么这可以在 XSLT 中完成,在声明中指定一个cdata-section-elements
属性。<xsl:output>
这是一个简短的例子:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"
cdata-section-elements="a b c d e"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
当此转换应用于以下 XML 文档时:
<Record>
<a>10:30</a>
<b>20:30</b>
<c>10:60</c>
<d>1:15</d>
<e>1:03</e>
</Record>
产生了想要的正确结果:
<Record>
<a><![CDATA[10:30]]></a>
<b><![CDATA[20:30]]></b>
<c><![CDATA[10:60]]></c>
<d><![CDATA[1:15]]></d>
<e><![CDATA[1:03]]></e>
</Record>
如果事先不知道一组元素名称,可以使用生成另一个样式表的样式表,该样式表应最终应用于 XML 文档以产生所需的结果:
<xsl:stylesheet version="1.0" xmlns:x="http://www.w3.org/1999/XSL/Transform"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xxx="xxx">
<xsl:namespace-alias stylesheet-prefix="xxx" result-prefix="xsl"/>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kElemByName" match="*[text()[normalize-space()]]" use="name()"/>
<xsl:variable name="vDistinctNamedElems" select=
"//*[generate-id()=generate-id(key('kElemByName',name())[1])]"/>
<xsl:variable name="vDistinctNames">
<xsl:for-each select="$vDistinctNamedElems">
<xsl:value-of select="concat(name(), ' ')"/>
</xsl:for-each>
</xsl:variable>
<xsl:template match="node()|@*">
<xxx:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xxx:output omit-xml-declaration="yes" indent="yes"
cdata-section-elements="{$vDistinctNames}"/>
<xxx:strip-space elements="*"/>
<xxx:template match="node()|@*">
<xxx:copy>
<xxx:apply-templates select="node()|@*"/>
</xxx:copy>
</xxx:template>
</xxx:stylesheet>
</xsl:template>
</xsl:stylesheet>
当此转换应用于同一个 XML 文档(上图)时,结果是另一个 XSLT 样式表:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="yes" indent="yes" cdata-section-elements="a b c d e "/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
在此样式表中,cdata-section-elements
属性中的所有元素名称都是动态生成的(使用 Muenchian 方法进行分组)。
当我们最终在同一个 XML 文档上应用如此生成的 XSLT 样式表时,我们得到了想要的结果:
<Record>
<a><![CDATA[10:30]]></a>
<b><![CDATA[20:30]]></b>
<c><![CDATA[10:60]]></c>
<d><![CDATA[1:15]]></d>
<e><![CDATA[1:03]]></e>
</Record>
说明:
使用 XSLT 指令动态生成新的转换xsl:namespace-alias
。
Muenchian 分组以确定所有不同的元素名称。