我的XSLT转换已成功几个月,直到我遇到一个带有Unicode字符的XML文件(很可能是表情符号)。我需要保留Unicode,但XSLT将其转换为HTML实体。我认为将编码设置为UTF-8可以解决我的问题,但我仍然遇到问题。
任何帮助表示赞赏。代码:
private byte[] transform(InputStream stream) throws Exception{
System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
Transformer xmlTransformer;
xmlTransformer = (TransformerImpl) TransformerFactory.newInstance().newTransformer(new StreamSource(createXsltStylesheet()));
xmlTransformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(stream,"UTF-8");
Source staxSource = new StAXSource(reader, true);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Writer writer = new OutputStreamWriter(outputStream, "UTF-8");
xmlTransformer.transform(staxSource, new StreamResult(writer));
return outputStream.toByteArray();
}
如果我添加
xmlTransformer.setOutputProperty(OutputKeys.METHOD, "text");
保留了Unicode,但XML不是。
答案 0 :(得分:0)
这一行很可疑:
stream = IOUtils.toInputStream(outputStream.toString(),"UTF-8");
您正在使用平台的默认编码将ByteArrayOutputStream
转换为字符串,该编码可能不是UTF-8。将其更改为
stream = IOUtils.toInputStream(outputStream.toString("UTF-8"),"UTF-8");
或者,为了获得更好的性能,只需将字节数组包装在ByteArrayInputStream
:
return new ByteArrayInputStream(outputStream.toByteArray());
答案 1 :(得分:0)
尝试使用Apache Serializer将XML转换为String。
//Serialize DOM
OutputFormat format = new OutputFormat (doc);
// as a String
StringWriter stringOut = new StringWriter ();
XMLSerializer serial = new XMLSerializer (stringOut,
format);
serial.serialize(doc);
// Display the XML
System.out.println(stringOut.toString());
答案 2 :(得分:0)
我只是遇到了同样的问题,经过长时间的研究,这就是我所得出的结论。
Java XSLT处理器将多字节UTF-8字符转换为HTML实体,即使输出模式是XML ...如果text()节点中出现多字节字符不是包裹在CDATA中。 如果字符包装在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.
猪食!
在命令行上使用xsltproc
进行测试是没用的,因为xsltproc
在涉及多字节字符时并不愚蠢。我得到了我预期的输出。
通过在eventComment
标记xsl:output
属性中指定QName,让XSLT在CDATA中包装cdata-section-elements
将保留字节并与xsltproc 和java Transformer一起使用强>
这里的神奇之处在于cdata-secion-elements
标记的输出<xsl: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>
答案 3 :(得分:0)
通过将以下行添加到原始XML来解决了类似的问题:
document.appendChild(document.createProcessingInstruction(StreamResult.PI_DISABLE_OUTPUT_ESCAPING, ""));
请参阅:Writing emoji to XML file in JAVA
也许可以对变压器使用类似的设置...