You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SaxonCS执行XSLT转换时输出出现多余换行,如何解决?

问题:XSLT转换后输出多余换行,及Serializer与直接ToString()的区别

原始XML文档

<DetailBill>
  <DetailBillInfo>
    <NoticeType>Detail Invoice</NoticeType>
    <Application>1</Application>
  </DetailBillInfo>
  <DetailBillInfo>
    <NoticeType>Detail Invoice</NoticeType>
    <Application>2</Application>
  </DetailBillInfo>
  <DetailBillInfo>
    <NoticeType>Detail Invoice</NoticeType>
    <Application>3</Application>
  </DetailBillInfo>
</DetailBill>

期望输出(制表符分隔文本)

NoticeType	Application
Detail Invoice	1
Detail Invoice	2
Detail Invoice	3

使用的XSLT样式表

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" indent="no" />
  <xsl:template match="/DetailBill">
    <xsl:text>NoticeType&#x9;Application&#xA;</xsl:text>
    <xsl:for-each select="DetailBillInfo">
      <xsl:value-of select="normalize-space(NoticeType)" />
      <xsl:text>&#x9;</xsl:text>
      <xsl:value-of select="normalize-space(Application)" />
      <xsl:text>&#xA;</xsl:text>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

.NET 8.0 + SaxonCS 12.4 原调用代码

System.Xml.Linq.XElement xml = System.Xml.Linq.XElement.Parse("{xml}");
System.Xml.Linq.XElement stylesheet = System.Xml.Linq.XElement.Parse("{xslt}");
Saxon.Api.Processor processor = new(true);
Saxon.Api.XsltCompiler comp = processor.NewXsltCompiler();
List<Saxon.Api.Error> errs = [];
comp.ErrorReporter = errs.Add;
Saxon.Api.XsltExecutable exe = comp.Compile(stylesheet.CreateReader());
Saxon.Api.Xslt30Transformer xfrm = exe.Load30();
Saxon.Api.XdmValue output = xfrm.ApplyTemplates(xml.CreateReader());

错误输出结果

NoticeType  Application

Detail Invoice
	
1


Detail Invoice
	
2


Detail Invoice
	
3

问题:上述操作哪里出错了?


更新:使用Serializer解决问题

改用Saxon.Api.Serializer后输出符合预期,修正后的C#代码如下:

System.Xml.Linq.XElement xml = System.Xml.Linq.XElement.Parse("{xml}");
System.Xml.Linq.XElement stylesheet = System.Xml.Linq.XElement.Parse("{xslt}");
Saxon.Api.Processor processor = new(true);
Saxon.Api.XsltCompiler comp = processor.NewXsltCompiler();
List<Saxon.Api.Error> errs = [];
comp.ErrorReporter = errs.Add;
Saxon.Api.XsltExecutable exe = comp.Compile(stylesheet.CreateReader());
Saxon.Api.Xslt30Transformer xfrm = exe.Load30();
Saxon.Api.Serializer ser = processor.NewSerializer();
System.Text.StringBuilder sb = new();
using System.IO.StringWriter sw = new(sb);
ser.OutputWriter = sw;
xfrm.ApplyTemplates(xml.CreateReader(), ser);

疑问:Serializer与直接调用output.ToString()的区别是什么?

核心区别说明:

  1. output.ToString()的行为:
    调用XdmValue.ToString()是对转换后生成的XDM文本节点集合进行默认序列化,Saxon会自动在每个文本节点之间添加换行符,导致输出出现多余空行。这种方式不遵循XSLT样式表中<xsl:output>的配置,只是简单拼接节点内容并添加默认分隔符。

  2. Serializer的行为:
    Serializer会严格遵循XSLT样式表中<xsl:output>的设置(比如method="text"、indent="no")处理输出,完全按照样式表定义的格式序列化转换结果,不会额外添加不必要的换行或分隔符,匹配样式表预期的输出格式。

内容的提问来源于stack exchange,提问作者JTennessen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 14:07:01