XSLT最常见的应用场景是把一份XML文档转换成HTML页面,但它的输出能力远不止HTML一种。当目标产物是CSV报表、SQL脚本、ini配置文件或者某种自定义格式的报文时,只要在样式表里把output的method属性设置为text,XSLT处理器就会丢弃所有标签结构,只把文本内容原样写入结果文档。这篇文章从底层行为讲起,配合完整实例,把文本输出模式的用法和容易踩的坑一次说清楚。

一、先搞清楚output的三种输出模式
XSLT规范里的xsl:output元素支持三种method取值:xml、html和text。前两种会序列化出带标签的文档,区别在于html模式会对结果做一些面向浏览器的特殊处理,比如把空元素序列化成<br>这种不带闭合斜杠的写法、对链接属性里的特殊字符做URL转义等。而text模式最特别,它在序列化阶段只保留结果树中的文本节点,所有元素节点连同属性都会被直接丢弃。
这个特性意味着一件事:即使你在样式表里构造了元素,只要method是text,最终文件里也看不到任何尖括号。反过来说,如果你希望输出结果里真的出现一段类似标签的文字,就必须通过xsl:text或者xsl:value-of把尖括号当作普通字符写出来。理解了这一点,后面所有关于文本输出的行为都能自己推导出来。
还要注意默认值的规则:如果没有写xsl:output,处理器会根据结果树的第一个节点自动判断,根节点是html元素时就用html模式,否则用xml模式。text永远不会被自动选中,所以想输出纯文本必须显式声明。
二、output method text的基础写法
下面用一个最小例子演示完整流程。假设有一份记录学生成绩的XML,我们想把它变成一行一个人的简单名单。
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student>
<name>张三</name>
<score>92</score>
</student>
<student>
<name>李四</name>
<score>87</score>
</student>
</students>样式表只需要几行就能完成转换:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/students">
<xsl:for-each select="student">
<xsl:value-of select="name"/>
<xsl:text> 得分:</xsl:text>
<xsl:value-of select="score"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>运行后得到两行纯文本:张三 得分:92,李四 得分:87。这里有几个细节值得展开。encoding属性控制输出文件的字符编码,中文内容一定要显式写成UTF-8或者GBK,否则在不同处理器上可能出现乱码。XML声明那行在text模式下天然不存在,不需要再额外配置。xsl:text元素的作用是原样输出其中的字符,包括空格,这是控制输出格式的主要手段。
换行符的写法也值得说明。上面例子里的 是XML字符引用,表示换行符。为什么不直接在样式表里敲回车?因为XSLT对样式表自身的空白有裁剪规则,直接敲的回车经常会被意外保留或裁掉,行为难以预测,用字符引用最稳妥。Windows下如果目标程序要求CRLF换行,可以写成 两个字符连用。
三、空白裁剪与格式控制的攻防战
文本输出最大的麻烦来自空白。样式表为了缩进好看,模板里到处是换行和空格,这些空白节点默认会被复制到结果里,让输出文件出现大量莫名其妙的空行。规范层面的解决办法是xsl:strip-space,它告诉处理器把源文档中只含空白的文本节点全部删掉:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="student">
<xsl:value-of select="name"/>,<xsl:value-of select="score"/>
</xsl:template>
</xsl:stylesheet>但strip-space只管源XML,管不了样式表自己的缩进。控制样式表空白的技巧有两个:一是把模板内容尽量写紧凑,让指令之间不留换行;二是把需要精确控制的片段全部包进xsl:text。xsl:text里的内容一字不差地输出,之外的空白则遵循XSLT的裁剪规则,两者配合基本能覆盖所有格式需求。
如果输出内容里有连续空格、制表符这类不可见字符,同样建议用字符引用表达,比如	表示制表符, 表示空格,这样即使样式表日后被格式化工具重新排版,输出结果也不会跟着变化。
四、实战案例:把订单XML导出成CSV文件
CSV是文本输出最典型的应用场景。下面的例子把订单数据导出成带表头的CSV,并且处理了字段内含逗号的转义问题,保证Excel打开时不会串列。
<?xml version="1.0" encoding="UTF-8"?>
<orders>
<order id="A001">
<customer>王五</customer>
<product>机械键盘,青轴</product>
<amount>399</amount>
</order>
<order id="A002">
<customer>赵六</customer>
<product>显示器支架</product>
<amount>159</amount>
</order>
</orders>对应的转换样式表如下:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<!-- 字段含逗号时用双引号包裹 -->
<xsl:template name="csv-field">
<xsl:param name="value"/>
<xsl:choose>
<xsl:when test="contains($value, ',')">
<xsl:text>"</xsl:text>
<xsl:value-of select="$value"/>
<xsl:text>"</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$value"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/orders">
<xsl:text>订单号,客户,商品,金额
</xsl:text>
<xsl:for-each select="order">
<xsl:value-of select="@id"/>
<xsl:text>,</xsl:text>
<xsl:call-template name="csv-field">
<xsl:with-param name="value" select="customer"/>
</xsl:call-template>
<xsl:text>,</xsl:text>
<xsl:call-template name="csv-field">
<xsl:with-param name="value" select="product"/>
</xsl:call-template>
<xsl:text>,</xsl:text>
<xsl:value-of select="amount"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>输出结果是标准的四行CSV,其中机械键盘那条的商品字段因为原文含逗号,会被双引号包起来。这个例子体现了文本模式的典型套路:数据用xsl:value-of取值,分隔符和换行用xsl:text拼接,复杂逻辑抽成命名模板复用。同样的思路稍加改造就能输出SQL插入语句、固定宽度的对账报文,或者yaml、ini这类配置文件。
五、常见问题排查
第一个高频问题是输出文件里多出空行或者行首多出空格,原因基本都指向空白处理,按上一节的方法用strip-space加xsl:text收紧即可。第二个问题是乱码,检查xsl:output的encoding是否与查看文件的编辑器编码一致;如果用Java的Transformer API调用,还要确认写文件的Writer本身没有再套一层错误编码。第三个容易困惑的点是转义行为:text模式下不会做任何XML转义,源文档里的&会被输出成&本身,这是正常现象,反而省去了反转义的步骤。
最后提醒一个边界情况:text模式下doctype-system、cdata-section-elements这些与标签结构相关的输出属性全部失效,写了也不报错但没有效果。如果发现某些输出属性不生效,先确认自己是不是处在text模式,避免在无效配置上浪费时间。掌握这些要点之后,XSLT就不再只是XML到HTML的转换工具,而是一条稳定可靠的文本文件生产线。
XSLToutput method text纯文本输出修改时间:2026-10-05 00:30:57