使用 msxsl:script 的脚本块

注意

只有 .NET Framework 支持脚本块。 .NET Core 或 .NET 5(或更高版本)不支持它们。

XslCompiledTransform 类使用 msxsl:script 元素支持嵌入的脚本。 在加载样式表式,任何已定义的函数将通过代码文档对象模型 (CodeDOM) 编译为公共中间语言 (CIL) 并在运行时执行。 从嵌入的脚本块生成的程序集比为样式表生成的程序集独立。

启用 XSLT 脚本

支持嵌入式脚本是 XslCompiledTransform 类上可选的 XSLT 设置。 默认情况下禁用脚本支持。 要启用脚本支持,创建一个 XsltSettings 对象,将 EnableScript 属性设置为 true,然后将该对象传递给 Load 方法。

注意

只有要求脚本支持并且处于完全可信的环境下时,才应启用 XSLT 脚本。

msxsl:script 元素定义

msxsl:script 元素是 Microsoft 对 XSLT 1.0 建议的扩展,包括以下定义:

<msxsl:script language = "language-name" implements-prefix = "prefix of user namespace"> </msxsl:script>

msxsl 前缀绑定到 urn:schemas-microsoft-com:xslt 命名空间 URI 上。 样式表必须包括 xmlns:msxsl=urn:schemas-microsoft-com:xslt 命名空间声明。

language 属性是可选项。 属性值是嵌入式代码块的代码语言。 该语言使用 CodeDomProvider.CreateProvider 方法映射到相应的 CodeDOM 编译器。 XslCompiledTransform 类可以支持任何 Microsoft .NET 语言,假定在计算机上已安装了相应的提供程序并且已在 machine.config 文件的 system.codedom 部分进行注册。 如果未指定 language 属性,则默认语言为 JScript。 语言名称不区分大小写,所以“JavaScript”和“javascript”等效。

implements-prefix 属性是必选项。 此属性用于声明命名空间并将其与脚本块关联。 此属性的值是表示命名空间的前缀。 此前缀可以在样式表中的某一位置定义。

注意

当使用 msxsl:script 元素时,强烈建议无论使用何种语言,都应将脚本放置在 CDATA 节内。 因为脚本可以包含给定语言的运算符、标识符或分隔符,如果不包含在 CDATA 节中,可能会错误地作为 XML 解释。 以下 XML 显示可以放入代码的 CDATA 节的模板。

<msxsl:script implements-prefix='your-prefix' language='CSharp'>
<![CDATA[
// Code block.
]]>
</msxsl:script>

脚本函数

函数可以在 msxsl:script 元素内声明。 声明函数时,该函数包含在脚本块中。 样式表可以包含多个脚本块,每个脚本块彼此独立运行。 也就是说,如果在脚本块的内部执行,则无法调用在其他脚本块中定义的函数,除非该脚本块声明为具有同一命名空间和同一脚本语言。 由于每个脚本块都可以使用自己的语言,因此脚本块的分析将遵照语言分析器的语法规则进行,我们建议您使用适合所使用语言的语法。 例如,如果在 Microsoft C# 脚本块中,请使用 C# 注释语法。

为函数提供的参数和返回值可以是任意类型。 因为 W3C XPath 类型是公共语言运行库 (CLR) 类型的子集,所以,对不属于 XPath 类型的类型进行类型转换。 下表显示相应的 W3C 类型和等效的 CLR 类型。

W3C 类型 CLR 类型
String String
Boolean Boolean
Number Double
Result Tree Fragment XPathNavigator
Node Set XPathNodeIterator

CLR 数字类型转换为 DoubleDateTime 类型转换为 StringIXPathNavigable 类型转换为 XPathNavigator。 XPathNavigator[] 转换为 XPathNodeIterator

所有其他类型均将引发错误。

导入命名空间和程序集

XslCompiledTransform 类预定义了一组程序集和命名空间,默认情况下,通过 msxsl:script 元素支持这些程序集和命名空间。 但是,可以通过在 msxsl:script 块中导入程序集和命名空间,使用属于不在预定义列表中的某个命名空间的类和成员。

程序集

默认情况下引用下列两个程序集:

  • System.dll

  • System.Xml.dll

  • Microsoft.VisualBasic.dll(如果脚本语言为 VB)

可以使用 msxsl:assembly 元素导入其他程序集。 包括在编译样式表时的程序集。 msxsl:assembly 元素具有以下定义:

<msxsl:script>
  <msxsl:assembly name="system.assemblyName" />
  <msxsl:assembly href="path-name" />
    <![CDATA[
    // User code
    ]]>
</msxsl:script>

name 属性包含程序集的名称,href 属性包含程序集的路径。 程序集名称可以是全名,例如“System.Data, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”,也可以是缩写名称,例如“System.Web”。

命名空间

默认情况下包括下列命名空间:

  • System

  • System.Collection

  • System.Text

  • System.Text.RegularExpressions

  • System.Xml

  • System.Xml.Xsl

  • System.Xml.XPath

  • Microsoft.VisualBasic(如果脚本语言为 VB)

可以使用 namespace 属性添加对其他命名空间的支持。 属性值是命名空间的名称。

<msxsl:script>
  <msxsl:using namespace="system.namespaceName" />
    <![CDATA[
    // User code
    ]]>
</msxsl:script>

示例

已知圆的半径,下面的示例使用嵌入脚本计算圆的周长。

using System;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;

public class Sample {

  private const String filename = "number.xml";
  private const String stylesheet = "calc.xsl";

  public static void Main() {

    // Compile the style sheet.
    XsltSettings xslt_settings = new XsltSettings();
    xslt_settings.EnableScript = true;
    XslCompiledTransform xslt = new XslCompiledTransform();
    xslt.Load(stylesheet, xslt_settings, new XmlUrlResolver());

    // Load the XML source file.
    XPathDocument doc = new XPathDocument(filename);

    // Create an XmlWriter.
    XmlWriterSettings settings = new XmlWriterSettings();
    settings.OmitXmlDeclaration = true;
    settings.Indent = true;
    XmlWriter writer = XmlWriter.Create("output.xml", settings);

    // Execute the transformation.
    xslt.Transform(doc, writer);
    writer.Close();
  }
}
Imports System.IO
Imports System.Xml
Imports System.Xml.XPath
Imports System.Xml.Xsl

Public class Sample

    Private Const filename As String = "number.xml"
    Private Const stylesheet As String = "calc.xsl"

    Public Shared Sub Main()

        ' Compile the style sheet.
        Dim xslt_settings As XsltSettings = New XsltSettings()
        xslt_settings.EnableScript = true
        Dim xslt As XslCompiledTransform = New XslCompiledTransform()
        xslt.Load(stylesheet, xslt_settings, New XmlUrlResolver())

        ' Load the XML source file.
        Dim doc As XPathDocument = New XPathDocument(filename)

        ' Create an XmlWriter.
        Dim settings As XmlWriterSettings = New XmlWriterSettings()
        settings.OmitXmlDeclaration = true
        settings.Indent = true
        Dim writer As XmlWriter = XmlWriter.Create("output.xml", settings)

        ' Execute the transformation.
        xslt.Transform(doc, writer)
        writer.Close()
    End Sub
End Class

number.xml

<?xml version='1.0'?>
<data>
  <circle>
    <radius>12</radius>
  </circle>
  <circle>
    <radius>37.5</radius>
  </circle>
</data>

calc.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  xmlns:user="urn:my-scripts">
  <msxsl:script language="C#" implements-prefix="user">
  <![CDATA[
  public double circumference(double radius){
    double pi = 3.14;
    double circ = pi*radius*2;
    return circ;
  }
  ]]>
  </msxsl:script>
  <xsl:template match="data">
    <circles>
      <xsl:for-each select="circle">
        <circle>
          <xsl:copy-of select="node()"/>
          <circumference>
            <xsl:value-of select="user:circumference(radius)"/>
          </circumference>
        </circle>
      </xsl:for-each>
    </circles>
  </xsl:template>
</xsl:stylesheet>

Output

<circles xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:user="urn:my-scripts">
  <circle>
    <radius>12</radius>
    <circumference>75.36</circumference>
  </circle>
  <circle>
    <radius>37.5</radius>
    <circumference>235.5</circumference>
  </circle>
</circles>

请参阅