I just遇到了同样的问题,经过长时间的研究,这就是我的结论。
Java XSLT 处理器将多字节 UTF-8 字符转义为 HTML 实体即使输出模式是 XML...如果多字节字符出现在未包装在 CDATA 中的 text() 节点中。如果字符包含在 CDATA 中(用于输出),则多字节字符将是保留.
我的问题:
我有一个如下所示的 xml 文件,其中包含表情符号。
<events>
<event>
<id>RANDOMID</id>
<blah>
<blahId>FOOONE</blahId>
</blah>
<blah>
<blahId>FOOTWO</blahId>
</blah>
<eventComment>Did some things. Had some Fun. ????</eventComment>
</event>
</events>
我从一个如下所示的 XSL 样式表开始:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/TR/xhtml1/strict"
>
<xsl:output method = "xml" version="1.0" encoding = "UTF-8" omit-xml-declaration="no" indent="yes" />
<xsl:template match="/">
<events>
<xsl:for-each select="/events/event">
<event>
<xsl:copy-of select="./*[name() != 'blah'"/>
<xsl:for-each select="./blah">
<blahId><xsl:copy-of select="./blahId/text()"/></blahId>
</xsl:for-each>
</event>
</xsl:for-each>
</events>
</xsl:template>
</xsl:stylesheet>
使用一致生成的 java Transformer 运行它��
我的表情符号应该在哪里。随后尝试解析结果文档失败,并显示以下异常消息:
org.xml.sax.SAXParseException; lineNumber: y; columnNumber: x; Character reference "�" is an invalid XML character.
HOGWASH!
测试这个xsltproc
在命令行上是没用的,因为xsltproc
当涉及到多字节字符时并不愚蠢。我得到了我期望的输出。
一个办法
让 XSLT 包装eventComment
通过在 CDATA 中指定 QNamexsl:output
tag cdata-section-elements
属性将保留字节并与 xsltproc 一起使用和java变压器.
这里的神奇之处在于输出cdata-secion-elements
财产来自<xsl:output>
tag. https://www.w3.org/TR/xslt#output https://www.w3.org/TR/xslt#output
我将 XSL 模板更新为:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/TR/xhtml1/strict"
>
<xsl:output cdata-section-elements="eventComment" method="xml" version="1.0" encoding="UTF-8" omit-xml-declaration="no" indent="yes"/>
<xsl:template match="/">
<events>
<xsl:for-each select="/events/event">
<event>
<xsl:copy-of select="./*[name() != 'blah' and name() != 'eventComment']"/>
<!-- For the cdata-section-elements to resolve that eventComment needs to be preserved as CDATA
(so we don't get java doing stupid things with unicode escapment)
it needs to be explicitly referenced here.
-->
<eventComment><xsl:copy-of select="./eventComment/text()"/></eventComment>
<xsl:for-each select="./blah">
<blahId><xsl:copy-of select="./blahId/text()"/></blahId>
</xsl:for-each>
</event>
</xsl:for-each>
</events>
</xsl:template>
</xsl:stylesheet>
现在我的输出xsltproc
java Transformer 看起来像这样,并且可以使用 java DocumentBuilders 愉快地解析。
<?xml version="1.0" encoding="UTF-8"?>
<events xmlns="http://www.w3.org/TR/xhtml1/strict">
<event>
<id xmlns="">RANDOMID</id>
<eventComment><![CDATA[Did some things. Had some Fun. ????]]></eventComment>
<blahId>FOO</blahId>
<blahId>FOOTOO</blahId>
</event>
</events>