XSLT作为将XML文档转换为HTML或其他格式的标准技术,在处理中文内容时经常遇到乱码现象。这种问题并非XSLT本身缺陷,而是编码配置在多个环节出现不一致所导致。要彻底解决,需要理解XML解析器、XSLT处理器以及最终输出通道各自对字符集的要求。

一、中文乱码产生的常见环节
在典型的XSLT转换流程中,至少存在三个与编码相关的关键点。第一是原始XML文档本身的存储编码与内部声明编码;第二是XSLT样式表文件的编码与<xsl:output>设置;第三是转换结果输出到客户端时HTTP响应头或文件保存格式所采用的编码。只要其中任意两者不匹配,中文字符便可能变成乱码。
例如,一个XML文件以UTF-8无BOM格式保存在磁盘,但文件开头写明了<?xml version="1.0" encoding="GBK"?>,部分解析器会以GBK去解码实际UTF-8字节,从而产生错误。同理,XSLT中若未显式设定输出编码,某些旧版处理器会默认使用UTF-8,而部署环境的Web服务器却以ISO-8859-1发送,浏览器自然无法正确渲染中文。
二、XML与XSLT文件本身的编码规范
确保源文件物理编码和声明编码一致,是消除乱码的第一步。推荐使用UTF-8保存所有XML及XSLT文件,并在文档头部明确声明。XML声明应写作<?xml version="1.0" encoding="UTF-8"?>,XSLT根节点内也应包含对应输出声明。
下面给出一个正确的XSLT模板头部示例,其中既指定了样式表文件自身期望的XML声明,也通过<xsl:output>告诉处理器最终输出HTML时要使用UTF-8:
<?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" indent="yes"/>
<xsl:template match="/">
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/></head>
<body>
<p><xsl:value-of select="root/title"/></p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
上述代码中的<meta>标签进一步在生成的HTML里标注了UTF-8,可防止浏览器自行猜测编码。注意如果XSLT文件自身不是UTF-8存储,却声明encoding="UTF-8",同样会引发解析错误,因此编辑器保存选项必须同步检查。
三、Java环境中使用XSLT时的编码控制
在Java程序里调用JAXP进行转换时,输入流与输出流都要显式绑定编码。很多开发者直接传入File对象,依赖系统默认编码,这在中文Windows上常为GBK,与UTF-8文件冲突。应当用InputStreamReader包装并指定UTF-8,输出则用OutputStreamWriter做同样处理。
以下代码片段展示了安全的转换写法:
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import java.io.*;
public class XsltDemo {
public static void main(String[] args) throws Exception {
TransformerFactory factory = TransformerFactory.newInstance();
// 样式表也以UTF-8读取
StreamSource xsl = new StreamSource(
new InputStreamReader(new FileInputStream("style.xsl"), "UTF-8"));
Transformer transformer = factory.newTransformer(xsl);
// XML源以UTF-8读取
StreamSource xml = new StreamSource(
new InputStreamReader(new FileInputStream("data.xml"), "UTF-8"));
// 输出以UTF-8写入
StreamResult result = new StreamResult(
new OutputStreamWriter(new FileOutputStream("out.html"), "UTF-8"));
transformer.transform(xml, result);
}
}
这段代码避免了平台默认编码干扰。如果部署在Tomcat等容器,还需在Servlet响应中设置response.setContentType("text/html;charset=UTF-8"),保证HTTP头与文档内声明一致。漏掉任何一处,都可能让前面所有努力白费。
四、浏览器与服务器端的协同配置
即便转换引擎输出了正确的UTF-8字节,若Web服务器发送的Content-Type响应头未带charset=UTF-8,浏览器便可能以本地编码打开页面。在Nginx或Apache中,应配置向XSLT生成路由返回正确的MIME类型与字符集。
对于静态生成的HTML文件,通过前面XSLT里的<meta>标签通常足够,但动态接口建议直接从HTTP头层面声明。下面给出一个简单的Nginx配置片段示意:
location /transformed/ {
default_type text/html;
add_header Content-Type "text/html; charset=UTF-8";
}
这样从传输协议层锁定编码,比单纯依赖文件内容声明更稳健。综合来看,解决XSLT中文乱码的核心在于全链路统一使用UTF-8,并在每一个可能丢失编码信息的节点主动声明,而不是等乱码出现后再做局部修补。