XSLT文件中缺少CDATA标记



我有一个xml文件:

<btask>
<instruction>client_save</instruction>
<section_data>
<client>
<mode_low>12200</mode_low>
<swift/>
<wcn/>
<okved_version>1</okved_version>
<add_info><![CDATA[<msg><kig>781/4</kig></msg>]]>
</add_info>
</client>
</section_data>
</btask>

我想要得到这样的xml:

<btask>
<instruction code="client_save"/>
<section_data>
<field code="mode_low">12200</field>
<field code="swift"/>
<field code="wcn"/>
<field code="okved_version">1</field>
<field code="add_info"><![CDATA[<msg><kig>781/4</kig></msg>]]></field>
</section_data>
</btask>

我已经写了一个这样做的xslt,但它总是缺少CDATA和编写规范图表,所以我得到了"add_info"标记:

<field code="add_info">&lt;msg&gt;&lt;kig&gt;781/4&lt;/kig&gt;&lt;/msg&gt;</field>

我怎么能解决这个问题?我试着用干净的xslt来做,它可以改变图表

***注意:我不需要一个清晰的xml,所以disable-output-escaping不适合我。

XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="group_fields"/>
<xsl:template match="/">
<xsl:element name="btask">
<xsl:for-each select="//btask/*[name()!='section_data' and name()!='section_data_tech' and name()!='instruction']">
<xsl:attribute name="{name()}">
<xsl:value-of select="./text()"/>
</xsl:attribute>
</xsl:for-each>
<xsl:if test="count(//btask/instruction) = 1">
<xsl:element name="instruction">
<xsl:attribute name="code">
<xsl:value-of select="//btask/instruction"/>
</xsl:attribute>
</xsl:element>
</xsl:if>
<xsl:for-each select="//btask/*[name()='section_data' or name()='section_data_tech']">
<xsl:call-template name="sectiondata">
<xsl:with-param name="e" select="."/>
</xsl:call-template>
</xsl:for-each>
</xsl:element>
</xsl:template>
<xsl:template name="sectiondata">
<xsl:param name="e"/>
<xsl:copy>
<xsl:for-each select="$e/*">
<xsl:call-template name="entity">
<xsl:with-param name="e" select="."/>
</xsl:call-template>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template name="entity">
<xsl:param name="e"/>
<xsl:element name="entity_data">
<xsl:attribute name="code">
<xsl:choose>
<xsl:when test="string-length($e/@code)">
<xsl:value-of select="$e/@code"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="name()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:for-each select="$e/*">
<xsl:choose>
<xsl:when test="count(./*)>0 or $group_fields=name()">
<!-- groupdata or entitydata-->
<xsl:choose>
<xsl:when test="count(./*/*)>0 or $group_fields=name()">
<!-- groupdata-->
<xsl:element name="group_data">
<xsl:attribute name="code">
<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:for-each select="./*">
<xsl:call-template name="entity">
<xsl:with-param name="e" select="."/>
</xsl:call-template>
</xsl:for-each>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<!-- entity-->
<xsl:call-template name="entity">
<xsl:with-param name="e" select="."/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<!-- field-->
<xsl:element name="field">
<xsl:attribute name="code">
<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:value-of select="normalize-space(.)"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

您可以更改:

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

:

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" cdata-section-elements="field"/>

但是,这也会影响您正在创建的其他field元素。如果这是一个问题,你将不得不求助于更非正统的方法。

注意,这两种方法都不会有问题:CDATA节中的转义文本和文本表示完全相同的内容。显然,您正在处理的目标应用程序不理解这一点。


***注:我不需要一个清晰的xml,所以省略-xml-declaration不适合我。

我不知道你这话是什么意思。

xsl:output上可用的选项允许您为所有命名为field的元素生成CDATA节,或者为它们中的任何一个生成CDATA节,但不为选定的元素生成CDATA节;在标准XSLT中没有办法确定输入是否使用了CDATA。

如果您确实需要对词法XML进行这种级别的控制,可以使用Andrew Welch提供的名为lexev的工具—它对源XML进行预处理,将CDATA部分转换为XSLT处理器可见的其他内容(元素或处理指令,我忘记了细节),然后对输出执行相反的后处理步骤。

理想情况下,应用程序真的不应该关心<a><![CDATA[<=>]]></a><a>&lt;=&gt;</a>之间的区别——它们只是表达同一事物的两种不同方式,应用程序应该将它们等同对待。

最新更新