在C#开发中处理异构系统数据交换时,经常需要把XML文档转换成另一种结构,比如生成HTML页面、平铺化数据给前端表格使用,或者把旧格式改写为新 schema。.NET Framework 和 .NET Core 都提供了 XslCompiledTransform 类,它是专门用于执行 XSLT 转换的高性能组件,内部会把样式表编译成公共中间语言以便重复利用。

XslCompiledTransform 的基础使用流程
使用 XslCompiledTransform 的第一步是实例化这个类。与早期版本的 XslTransform 不同,XslCompiledTransform 在构造时不会立即加载任何样式表,而是把编译过程推迟到调用 Load 方法时进行。这样的设计让你可以安全地复用同一个实例去执行多次转换,只要样式表相同就不需要重复解析。
Load 方法有多种重载,最常见的是直接传入 xslt 文件路径,或者传入一个 XmlReader 来读取样式表内容。如果样式表写在嵌入式资源里,也可以通过 Assembly 获取流再包成 XmlReader。下面的代码演示了从文件加载并转换 XML 到 HTML 的最简形式。
using System;
using System.Xml;
using System.Xml.Xsl;
class Program
{
static void Main()
{
XslCompiledTransform xslt = new XslCompiledTransform();
// 加载样式表文件
xslt.Load("report.xslt");
// 执行转换,输出到新文件
xslt.Transform("source.xml", "result.html");
}
}
上面的例子虽然简短,但已经覆盖了核心调用链:实例化、加载、转换。需要注意的是,Transform 方法同样有多个重载,可以接受 XmlReader、IXPathNavigable 或者纯文件路径作为源,也能把结果写到 XmlWriter、Stream 或者文件路径。在 Web 应用中,通常把结果写到 MemoryStream 再转成字符串返回给响应。
另一个容易忽略的点是编译选项。XslCompiledTransform 的 Load 方法有一个接受 XsltSettings 的重载,通过它可以开启或禁止诸如文档函数、脚本执行等特性。默认情况下这些危险特性是关闭的,这比旧版类安全很多。如果你确实要在样式表里写脚本,必须显式传入允许脚本的设置,并清楚这会带来代码执行风险。
处理命名空间与传递参数
真实项目里的 XML 往往带有命名空间,例如 SOAP 消息或者 Office 文档格式。如果样式表不匹配命名空间,模板永远命中不了节点。解决方式是样式表根元素用 xmlns 声明同样的命名空间前缀,并在 XPath 表达式里使用前缀。XslCompiledTransform 会严格按命名空间 URI 做匹配,而不是只看标签名。
除了静态样式表,很多场景需要动态控制输出,比如根据当前语言输出不同标题。这时要用 XsltArgumentList 向样式表传参。你在样式表里用 <xsl:param> 声明参数,C# 侧构造 XsltArgumentList 并调用 AddParam 放入值,最后在 Transform 时作为额外参数传入。下面代码展示如何传递一个字符串参数。
using System;
using System.Xml;
using System.Xml.Xsl;
class Program
{
static void Main()
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load("letter.xslt");
XsltArgumentList args = new XsltArgumentList();
args.AddParam("recipient", "", "张三");
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (XmlWriter writer = XmlWriter.Create("out.xml", settings))
{
xslt.Transform("input.xml", args, writer);
}
}
}
参数命名时第一个字符串是参数名,第二个是命名空间,留空表示无命名空间。如果样式表里的参数有命名空间,这里也要填一样的 URI,否则接收不到。传参机制让同一份 XSLT 能应对多租户或多语言环境,不必为每种情况维护独立文件。
在处理带命名空间的源文档时,建议用 XmlReaderSettings 的 DtdProcessing 属性控制是否解析 DTD,避免外部实体注入。虽然 XslCompiledTransform 默认比旧组件安全,但读取源 XML 的 reader 配置仍由调用方负责,不能掉以轻心。
性能优化与常见错误排查
XslCompiledTransform 之所以叫 Compiled,是因为它把 XSLT 编译成了程序集,第二次转换同一样式表时几乎零解析成本。因此千万不要在每次请求里都 new 一个新实例并 Load 文件,应当把编译好的实例缓存起来,比如放在静态字段或依赖注入单例里。对于高频服务,这种缓存能降低数十倍延迟。
常见错误之一是文件路径问题。Load 的相对路径基于当前工作目录而非代码文件目录,在 IIS 或 Docker 里工作目录可能不同,导致找不到 xslt。更稳妥的做法是用 Path.Combine 配合 AppContext.BaseDirectory 拼出绝对路径,或者把样式表作为嵌入资源读取。另一个错误是样式表本身有语法问题,此时 Load 会抛出 XsltException,信息里包含行号,应据此修正而非怀疑 API。
using System;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
class Transformer
{
private static readonly XslCompiledTransform _xslt = Build();
private static XslCompiledTransform Build()
{
string path = Path.Combine(AppContext.BaseDirectory, "templates", "main.xslt");
XslCompiledTransform t = new XslCompiledTransform();
t.Load(path);
return t;
}
public string Convert(string xml)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
using (StringWriter sw = new StringWriter())
using (XmlWriter xw = XmlWriter.Create(sw))
{
_xslt.Transform(doc, null, xw);
return sw.ToString();
}
}
}
上面的单例模式把编译动作放在静态构造函数里,整个进程只编译一次。Convert 方法接受 XML 字符串,用 XmlDocument 加载后转换到 StringWriter。这种方式在 Web API 中非常实用,既避免了重复 IO,也隔离了文件读取时机。
当转换结果不符合预期时,优先检查样式表的模板优先级和匹配模式。XSLT 的匹配规则较为复杂,多个模板可能同时匹配一个节点,此时取决于优先级和导入顺序。借助 xsl:message 在样式表里输出调试信息,可以快速定位是哪一步丢了数据。掌握这些细节后,XslCompiledTransform 就能成为你处理 XML 转换任务时稳定而强大的工具。
XslCompiledTransformXML转换XSLT修改时间:2026-08-15 20:02:16