我需要完成同样的任务。我已经用两个 xslt 解决了。
让我强调一下,这只有在 CDATA 是 well-formed xml 时才有效。
为了完整起见,让我在您的示例 xml 中添加一个根元素:
<root>
<well-formed-content><![CDATA[ Some Text <p>more text and tags</p>]]>
</well-formed-content>
</root>
图 1.- 启动 xml
第一步
在第一个转换步骤中,我将所有文本节点包装在一个新引入的 xml 实体old_text:
<?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="no" version="1.0"
encoding="UTF-8" standalone="yes" />
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="*|text()|@*|comment()|processing-instruction()" />
</xsl:copy>
</xsl:template>
<!-- Attribute-nodes and comment-nodes: Pass through without modifying -->
<xsl:template match="@*|comment()|processing-instruction()">
<xsl:copy-of select="." />
</xsl:template>
<!-- Text-nodes: Wrap them in a new node without escaping it. -->
<!-- (note precondition: CDATA should be valid xml. -->
<xsl:template match="text()">
<xsl:element name="old_text">
<xsl:value-of select="." disable-output-escaping="yes" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
图 2.- 第一个 xslt(将 CDATA 包装在“old_text”元素中)
如果您将此转换应用于起始 xml,这就是您得到的(我没有重新格式化它以避免混淆谁在做什么):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><root><old_text>
</old_text><well-formed-content><old_text> Some Text <p>more text and tags</p>
</old_text></well-formed-content><old_text>
</old_text></root>
图 3.- 转换后的 xml(第一步)
第二步
您现在需要清理引入的old_text 元素,并重新转义未创建新节点的文本:
<?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="no" version="1.0"
encoding="UTF-8" standalone="yes" />
<!-- Element-nodes: Process nodes and their children -->
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="*|text()|@*|comment()" />
</xsl:copy>
</xsl:template>
<!-- Attribute-nodes and comment-nodes: Pass through without modifying -->
<xsl:template match="@*|comment()">
<xsl:copy-of select="." />
</xsl:template>
<!--
'Wrapper'-node: remove the wrapper element but process its children.
With this matcher, the "old_text" is cleaned, but the originally CDATA
well-formed nodes surface in the resulting xml.
-->
<xsl:template match="old_text">
<xsl:apply-templates select="*|text()" />
</xsl:template>
<!--
Text-nodes: Text here comes from original CDATA and must be now
escaped. Note that the previous rule has extracted all the existing
nodes in the CDATA. -->
<xsl:template match="text()">
<xsl:value-of select="." disable-output-escaping="no" />
</xsl:template>
</xsl:stylesheet>
图 4.- 2nd xslt(清理后的人工引入元素)
结果
这是最终结果,最初在 CDATA 中的节点在您的新 xml 文件中展开:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><root>
<well-formed-content> Some Text <p>more text and tags</p>
</well-formed-content>
</root>
图 5.- 最终 xml
警告
如果您的 CDATA 包含 xml 中不支持的 html 字符实体(请查看此wikipedia article about character entities 中的示例),您需要将这些引用添加到您的中间 xml。让我用一个例子来说明这一点:
<root>
<well-formed-content>
<![CDATA[ Some Text <p>more text and tags</p>,
now with a non-breaking-space before the stop: .]]>
</well-formed-content>
</root>
图6.-在图1的xml中添加字符实体&nbsp;
图 2 中的原始 xslt 会将 xml 转换为:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><root><old_text>
</old_text><well-formed-content><old_text>
Some Text <p>more text and tags</p>,
now with a non-breaking-space before the stop: .
</old_text></well-formed-content><old_text>
</old_text></root>
图 7.- 第一次尝试转换图 6 中的 xml 的结果(格式不正确!)
这个文件的问题是它的格式不正确,因此不能用 XSLT 处理器进一步处理:
实体“nbsp”被引用,但未声明。
XML 检查完成。
图 8.- 图 7 中 xml 的格式良好检查结果
这种解决方法可以解决问题(match="/" 模板添加了&nbsp; 实体):
<?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="no" version="1.0"
encoding="UTF-8" standalone="yes" />
<!-- Add an html entity to the xml character entities declaration. -->
<xsl:template match="/">
<xsl:text disable-output-escaping="yes"><![CDATA[<!DOCTYPE root
[
<!ENTITY nbsp " ">
]>
]]>
</xsl:text>
<xsl:apply-templates select="*" />
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="*|text()|@*|comment()|processing-instruction()" />
</xsl:copy>
</xsl:template>
<!-- Attribute-nodes and comment-nodes: Pass through without modifying -->
<xsl:template match="@*|comment()|processing-instruction()">
<xsl:copy-of select="." />
</xsl:template>
<!-- Text-nodes: Wrap them in a new node without escaping it. -->
<!-- (note precondition: CDATA should be valid xml. -->
<xsl:template match="text()">
<xsl:element name="old_text">
<xsl:value-of select="." disable-output-escaping="yes" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
图 9.- xslt 创建实体声明
现在,在将这个 xslt 应用到 图 6 源 xml 之后,这是中间 xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!DOCTYPE root
[
<!ENTITY nbsp " ">
]>
<root><old_text>
</old_text><well-formed-content><old_text>
Some Text <p>more text and tags</p>,
now with a non-breaking-space before the stop: .
</old_text></well-formed-content><old_text>
</old_text></root>
图 10.- 中间 xml(图 3 中的 xml 加上实体声明)
您可以使用 图 4 中的 xslt 转换来生成最终的 xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><root>
<well-formed-content>
Some Text <p>more text and tags</p>,
now with a non-breaking-space before the stop: .
</well-formed-content>
</root>
图 11.- 将 html 实体转换为 UTF-8 的最终 xml
注意事项
对于这些示例,我使用了 NetBeans 7.1.2 内置 XSLT 处理器 (com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl - default JRE XSLT processor)
免责声明:我不是 XML 专家。我觉得这应该更容易......