使用XSLT转换XML并保留Unicode字符

我的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。

这条线是可疑的:

 stream = IOUtils.toInputStream(outputStream.toString(),"UTF-8"); 

您正在使用平台的默认编码将ByteArrayOutputStream转换为String,该编码可能不是UTF-8。 将其更改为

 stream = IOUtils.toInputStream(outputStream.toString("UTF-8"),"UTF-8"); 

或者,为了获得更好的性能,只需将字节数组包装在ByteArrayInputStream

 return new ByteArrayInputStream(outputStream.toByteArray()); 

尝试使用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()); 

刚刚遇到了同样的问题,经过长时间的研究,这就是我的结论。

即使输出模式是XML, Java XSLT处理器也会将多字节UTF-8字符转换为HTML实体…如果多字节字符出现在未包含在CDATA中的text()节点中。 如果字符包装在CDATA中(用于输出),则将保留多字节字符。

我的问题:

我有一个看起来像这样的xml文件,带有表情符号。

   RANDOMID  FOOONE   FOOTWO  Did some things. Had some Fun. 👍   

我从一个看起来像这样的XSL样式表开始:

                

使用java Transformer执行此操作始终如一地生成�� 我的表情符号应该在哪里。 解析生成的Document的后续尝试失败,并显示以下exception消息:

 org.xml.sax.SAXParseException; lineNumber: y; columnNumber: x; Character reference "�" is an invalid XML character. 

废话!

在命令行上使用xsltproc进行测试是没用的,因为xsltproc在涉及多字节字符时不是傻瓜。 我得到了我预期的输出。

一个办法

通过在xsl:output标记中指定QName,让XSLT将事件包装在CDATA中, cdata-section-elements属性将保留字节并与xsltproc 和java Transformer一起使用

这里的魔力是来自标记的输出cdata-secion-elements属性。 https://www.w3.org/TR/xslt#output

我将我的XSL模板更新为:

                  

现在我的xsltproc和java Transformer的输出都是这样的,并且使用java DocumentBuilders快乐地解析。

    RANDOMID  FOO FOOTOO