
在使用 .net 的 xslt 转换生成 html 时,`xsl:value-of` 默认会正确转义文本节点,但属性值(如 `value` 或自定义 `data-*` 属性)中的内联表达式不会自动转义,导致 xss 风险;需通过 xhtml 输出方法或手动编码确保所有上下文均安全。
在标准 .NET System.Xml.Xsl(仅支持 XSLT 1.0)中,
✅ 正确方案:使用 method="xhtml"(推荐)
XHTML 输出模式强制所有属性值和文本内容遵循 XML 编码规则,天然支持统一转义。但注意:原生 .NET Framework / .NET Core 的 XslCompiledTransform 不支持 XSLT 2.0/3.0 或 xhtml 方法。因此必须借助第三方处理器:
▪ 使用 SaxonCS(.NET 6+ 推荐)
SaxonCS(Saxon 11/12,商业版)原生支持 XSLT 3.0 和 xhtml 输出,配置简洁且可靠:
<!-- .csproj --> <PackageReference Include="SaxonCS" Version="12.4" />
using Saxon.CSharp.Api; var processor = new Processor(); var compiler = processor.NewXsltCompiler(); var stylesheet = compiler.Compile(xslt); // xslt 中 <xsl:output method="xhtml" ... /> var transformer = stylesheet.Load(); var input = processor.NewDocumentBuilder().Build(xml); using var output = new StringWriter(); transformer.Run(new Serializer(output)); Console.WriteLine(output.ToString());
对应 XSLT 片段应明确声明:
立即学习“前端免费学习笔记(深入)”;
<xsl:output method="xhtml" indent="yes" html-version="5.0" doctype-system="about:legacy-compat" omit-xml-declaration="yes"/>
✅ 效果:data-title 和 value 属性中的 /Contact/Name 值将被自动 HTML-encode(< →
▪ 兼容旧框架:Saxon HE + IKVM(.NET Framework)
若受限于 .NET Framework,可使用 IKVM 将 Java 版 Saxon HE 11.4 跨编译为 .NET 程序集(需额外配置 XML Resolver)。详见 GitHub 示例项目。
⚠️ 替代方案(不推荐,仅作兜底)
若无法引入 Saxon,可在 XSLT 中手动调用编码函数(需扩展对象):
<!-- 在 XSLT 中注册 C# 扩展函数 -->
<xsl:stylesheet ... xmlns:util="urn:utils">
<xsl:template match="/">
<input type="text" value="{util:HtmlEncode(/Contact/Name)}"/>
</xsl:template>
</xsl:stylesheet>并在 C# 中实现:
var args = new XsltArgumentList();
args.AddExtensionObject("urn:utils", new HtmlEncoderHelper());但此方式耦合度高、维护成本大,且易遗漏上下文(如 JSON 字符串内嵌属性),强烈建议优先采用 xhtml 输出模式。
? 关键总结
- method="html" 是“宽松渲染模式”,不保证属性值转义,不适合含用户数据的 HTML 输出;
- method="xhtml" 是“严格 XML 模式”,所有内容按 XML 规则序列化,天然防御 XSS;
- .NET 原生 XslCompiledTransform 无法满足需求,必须升级至 SaxonCS(现代 .NET)或 Saxon HE + IKVM(旧框架);
- 永远避免在 HTML 属性中拼接未经转义的动态内容——这是前端安全的黄金法则。











