使用Xalan进行XSLT转换时Emoji编码异常问题求助
XSLT中Xalan转换器处理Emoji编码异常的解决方案
问题背景
用XSLT生成HTML时碰到Emoji处理异常,测试不同转换引擎的表现:
- Saxon转换器:能正确输出Emoji
- Java内置Xalan转换器(
com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl):textarea里的Emoji显示正常,但input标签的value属性中Emoji编码错误 - Xalan 2.7.2:问题更严重
因许可证限制,优先用Xalan转换器,需要解决Emoji的正确处理问题。
测试代码
Java转换代码
TransformerFactory factory = TransformerFactory.newInstance( "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl", null); Transformer transformer = factory.newTransformer(new StreamSource(xsl)); DocumentSource domSource = new DocumentSource(doc); OutputStream stream = response.getOutputStream(); transformer.transform(domSource, new StreamResult(stream)); stream.flush(); stream.close();
(注:doc为dom4j文档,xsl为测试样式表输入流,response为HttpServletResponse对象)
测试用XSL样式表
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" encoding="UTF-8"/> <xsl:template match="/"> <xsl:text disable-output-escaping="yes"><!doctype html></xsl:text> <html> <head> <meta charset="UTF-8"/> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> </head> <body> <textarea>👍🏻</textarea><br/> <input type="text" value="👍🏻"/> </body> </html> </xsl:template> </xsl:stylesheet>
解决方法
1. 显式设置响应编码
除了XSL中指定<xsl:output encoding="UTF-8"/>,还要给HttpServletResponse明确设置编码,避免容器默认编码干扰:
// 在获取输出流前添加这两行 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=UTF-8"); OutputStream stream = response.getOutputStream();
2. 调整XSL中属性的写法
Xalan处理HTML属性时的转义逻辑可能有问题,改用xsl:attribute来定义input的value属性,避免直接写在标签内:
<!-- 替换原input标签 --> <input type="text"> <xsl:attribute name="value">👍🏻</xsl:attribute> </input>
如果还是有问题,可以尝试禁用属性值的输出转义(注意仅在确认内容安全时使用):
<input type="text"> <xsl:attribute name="value"> <xsl:text disable-output-escaping="yes">👍🏻</xsl:text> </xsl:attribute> </input>
3. 升级Xalan版本
Xalan 2.7.2存在字符编码相关bug,升级到2.7.3及以上版本(需确认许可证符合要求),部分后续版本修复了UTF-8多字节字符在属性中的转义问题。
4. 转换dom4j文档的输入方式
直接用dom4j文档生成DOMSource可能导致字符编码丢失,先把dom4j文档序列化为UTF-8编码的XML流,再用StreamSource传入转换器:
// 将dom4j文档转为UTF-8字节流 ByteArrayOutputStream baos = new ByteArrayOutputStream(); OutputFormat format = OutputFormat.createPrettyPrint(); format.setEncoding("UTF-8"); XMLWriter writer = new XMLWriter(baos, format); writer.write(doc); // 使用StreamSource代替DocumentSource StreamSource source = new StreamSource(new ByteArrayInputStream(baos.toByteArray())); transformer.transform(source, new StreamResult(stream));
内容的提问来源于stack exchange,提问作者morbac
相关产品推荐
相关产品推荐

