XslTransform 类支持使用 script 元素的嵌入脚本撰写。加载样式表时,任何已定义的函数都会通过包装在类定义中来编译为 Microsoft 中间语言 (MSIL),因此不会有任何性能损失。

<msxsl:script> 元素定义如下:

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

其中 msxsl 是绑定到命名空间 urn:schemas-microsoft-com:xslt 的前缀。

language 属性不是强制的,但如果指定,则它的值必须是下列语言之一:C#、VB、JScript、JavaScript、VisualBasic 或 CSharp。如果未指定,则默认语言为 JScript。language-name 不区分大小写,因此“JavaScript”和“javascript”是等效的。

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

因为 msxsl:script 元素属于命名空间 urn:schemas-microsoft-com:xslt,因此样式表必须包含命名空间声明 xmlns:msxsl=urn:schemas-microsoft-com:xslt

如果脚本的调用方没有 UnmanagedCode 访问权限,则样式表中的脚本将永不编译并且对 Load 的调用将失败。

如果调用方有 UnmanagedCode 权限,则脚本将编译,但允许的操作取决于加载时提供的证据。

如果您在使用采用 XmlReaderXPathNavigator 作为参数的 Load 方法之一加载样式表,则需要使用采用 Evidence 作为其中的一个参数的 Load 重载。为提供证据,调用方必须有为脚本程序集提供 EvidenceControlEvidence 权限。如果调用方没有此权限,则可以将 Evidence 参数设置为空值。这会导致在 Load 函数发现脚本时失败。ControlEvidence 权限是一种权力很大的权限,只应授予高度可信任的代码。

若要从您的程序集中得到证据,请使用 this.GetType().Assembly.Evidence。若要从 URI 得到证据,请使用 Evidence e = XmlSecureResolver.CreateEvidenceForUrl(stylesheetURI)

如果使用采用 XmlResolver 作为参数但没有 EvidenceLoad 方法,则程序集的安全区域默认为“完全信任”。有关更多信息,请参见 SecurityZone命名的权限集

函数可以在 msxsl:script 元素内声明。下表显示了默认情况下支持的命名空间。可以在列出的命名空间的外部使用类。然而,这些类必须是完全限定的。

默认命名空间 说明
System 系统类。
System.Collection 集合类。
System.Text 文本类。
System.Text.RegularExpressions 正则表达式类。
System.Xml 核心 XML 类。
System.Xml.Xsl XSLT 类。
System.Xml.XPath XPath 类。
Microsoft.VisualBasic 用于 Visual Basic 脚本的类。

声明函数时,该函数包含在脚本块中。样式表可以包含多个脚本块,它们的运行彼此独立。也就是说,如果在脚本块的内部执行,则无法调用在其他脚本块中定义的函数,除非该脚本块声明为具有同一命名空间和同一脚本语言。由于每个脚本块都可以使用自己的语言,因此脚本块的分析将遵照该语言分析器的语法规则进行。使用的语法对于所用的语言而言必须是正确的。例如,如果使用的是 C# 脚本块,则在该块中使用 XML 注释节点 <!-- an XML comment --> 是错误的。

所提供的参数以及由脚本函数定义的返回值必须是 W3C XPath 或 XSLT 类型之一。下表显示了相应的 W3C 类型、等效的 .NET 类(类型),以及 W3C 类型是 XPath 类型还是 XSLT 类型。

类型 等效的 .NET 类(类型) XPath 类型或 XSLT 类型
String System.String XPath
Boolean System.Boolean XPath
Number System.Double XPath
结果树片段 System.Xml.XPath.XPathNavigator XSLT
节点集 System.Xml.XPath.XPathNodeIterator XPath

如果脚本函数使用下列数值类型之一:Int16、UInt16、Int32、UInt32、Int64、UInt64、Single 或 Decimal,这些类型将被强制指定为 Double,而 Double 映射为 W3C XPath 类型数字。所有其他类型都通过调用 ToString 方法强制转换为字符串。

如果脚本函数使用上述类型以外的类型,或者如果函数在样式表加载到 XslTransform 对象中时不进行编译,则会引发异常。

当使用 msxsl:script 元素时,强烈建议无论使用何种语言,都应将脚本放置在 CDATA 节内。例如,下面的 XML 显示放置代码的 CDATA 节的模板。

<msxsl:script implements-prefix='yourprefix' language='CSharp'>
    <![CDATA[
    ... your code here ...
    ]]>
</msxsl:script>

强烈建议将所有脚本内容都放置在 CDATA 节内,因为给定语言的运算符、标识符或分隔符有可能被错误地解释为 XML。下面的示例显示如何在脚本中使用逻辑 AND 运算符。(这是根据XML的特性决定的解决方案,因为特殊字符的存在所以必须放在CDATA区域内)

<msxsl:script implements-prefix='yourprefix' language='CSharp>
    public string book(string abc, string xyz)
    {  if ((abc== abc)&&(abc== xyz)) return bar+xyz;
        else return null;
    }
</msxsl:script>

由于“&”符没有转义,因此这将引发异常。将文档作为 XML 加载,并且不对 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() {

    //Create the XslTransform and load the stylesheet.
    XslTransform xslt = new XslTransform();
    xslt.Load(stylesheet);

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

    //Create an XmlTextWriter to output to the console.             
    XmlTextWriter writer = new XmlTextWriter(Console.Out);
    writer.Formatting = Formatting.Indented;

    //Transform the file.
    xslt.Transform(doc, null, writer, null);
    writer.Close();
  } 
}

输入

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>

输出

<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>