网站导航网学 原创论文 原创专题 网站设计 最新系统 原创论文 论文降重 发表论文 论文发表 UI设计定制 论文答辩PPT格式排版 期刊发表 论文专题
返回网学首页
网学原创论文
最新论文 推荐专题 热门论文 论文专题
当前位置: 网学 > 设计资源 > .Net编程 > 正文

在.Net中扩展Xslt功能之脚本篇

论文降重修改服务、格式排版等 获取论文 论文降重及排版 论文发表 相关服务

为什么要扩展Xslt样式表功能

基于Xml的可扩展样式表语言Xsl及其转换Xslt实现了将Xml源文件从一种格式到另一种格式的转换。通过在xsl文件中定义一系列遵守规则的模板,匹配这些模板的Xml文档部分就能够被转换为可显示的Html页面文件、符合其他需要的Xml文件或除此之外其他结构的文件。当在Xslt文档中这样做时,没有明显的流程控制,也没有传统编程意义上的算法,甚至不需要任何程序代码和编程语言。绝大多数时候,这能够很好地完成任务。

任何一门语言都不可能绝对完善,而Xsl毕竟只是一门标记语言,单纯依靠它并不能完成所有任务。如同没有XPath、Xslt时,Xml充其量只能是一些标记的集合,什么也不能做一样。尤其,如果我们所需求的不仅仅是改变文档的显示方式或结构,我们还需要对文档进行更多的控制时,单纯使用Xslt的局限性就暴露出来了。比如,获取用户键入的参数以控制转换输出、连接外部数据源以及引用某种计算的结果等等,这些情况下,单纯使用Xslt这样的描述语言无法提供满意的解决方案。而我们知道,程序代码会很轻易地解决这些问题。

使用嵌入式脚本扩展Xslt样式表功能

Xml是易于扩展的,这也正是其短时间内能被广泛接受的原因之一。而Xslt完全基于xml实现,它应该也是易于扩展的。事实的确如此,W3C推荐标准的Xslt提供了针对不同处理器/解析器的专门的扩展。基本上,不同处理器/解析器可以在Xpath表达式、Xslt模板主体内容或顶级元素中使用扩展函数。而且,同任何程序语言的函数/方法一样,这些扩展函数可以用来完成所要求的子功能,它们也能够“一次定义,多次调用”。更重要地,这些嵌入脚本函数不仅能在xslt标记语言中调用,还能够运用在高级语言中。脚本语言所提供的组功能比纯Xslt所提供的功能更丰富,经常可以用来对文档内容进行更复杂的操作(例如对其应用科学计算或访问外部信息源等),这个特性大大扩展了xslt的功能。

实现时,需要在一个指定的命名空间中限定所创建的扩展函数,并且在特定的Xslt处理器中提供实现。之所以必须使用命名空间,是因为命名空间不仅可以防止不同来源的Xslt名称间的冲突。更重要的是它还将扩展予以标识,这样其他的处理器就可以忽略这个专门针对特定处理器的实现,并依靠这个命名空间在Xslt其他部分引用扩展函数。

MSXML XSLT处理器使用<msxsl:script>元素及其属性implements-prefix实现并扩展函数以提供脚本级支持。微软特别指定的命名空间允许MSXML XSLT处理器在样式表内定位脚本代码。<msxsl:script>元素的language属性告诉运行期脚本使用哪个解释程序,而implements-prefix属性值是扩展函数的前缀,这个前缀xslt文档的其他地方被声明。定义这些属性之后,Xslt处理器就能够使用这些信息调用解释器运行时脚本(如C#编译器)并在<msxsl:script>元素中实现扩展函数的代码编写。在样式表的其他地方,依靠<xsl:value-of>元素提供输出的模板通过seletct属性与扩展函数相关联,比如,执行并输出扩展函数的计算结果。

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

  1. <msxsl:script language="language-name"  implements-prefix="prefix of user's  
  2. namespace"></msxsl:script> 

其中:

language属性表示语言选项,它与html页面上script元素的language属性极为类似,其值提供函数/方法定义所用的脚本语言。不过,language属性不是必须的,但如果指定,则它的值必须是下列语言之一:C#、VB、JScript、JavaScript、VisualBasic或CSharp。如果未指定,则默认语言为JScript。与其他Xslt元素及属性严格区分大小写不同的是,这里的语言名称不区分大小写,因此,"JavaScript"和"javascript"是等效的。

implements-prefix属性是强制的。用于指定命名空间前缀并将其与脚本块关联。属性的值表示命名空间前缀。前缀所代表的命名空间必须在样式表中的某个位置定义。

同其他任何Xml元素标记一样,<msxsl:script>元素中的"msxsl"表示命名空间前缀。不过,名字"msxsl"并不重要,也就是说,并不一定非是"msxsl"不可,你一样可以命名为其他的字符串,比如:  

  1. xmlns:myxsl="urn:schemas-microsoft-com:xslt"  
  2. xmlns:myns="urn:schemas-microsoft-com:xslt" 

这样,命名空间前缀变为了"myxsl"或者"myns",相应地,元素<msxsl:script>就将改为<myxsl:script>或<myns:script>。这种改变不会对结果有什么影响,如果你在你的xslt文档所有部分保持一致的话。(在本文中,所有出现<script>元素的地方使用了msxsl,是为了与微软默认设置保持一致)

不知你是否已经注意到,上面的语句中,不管命名空间前缀怎样改变,其值却始终是urn:schemas-microsoft-com:xslt。这是必须的。要正确扩展xslt样式表功能,就必须指定这个命名空间。命名空间urn:schemas-microsoft-com:xslt符合W3C推荐标准,并在微软MSXML3.0以上处理器中提供支持。使用它不仅能在xslt中进行嵌入脚本编程,还能对其他扩展功能提供支持。比如,在xsl中使用node-set()函数。

通常,在<xsl:stylesheet>元素内定义<msxsl:script>元素,然后在<msxsl:script>元素内定义扩展函数,还可以在<msxsl:script>中实例化COM对象,这将大大扩展纯Xslt的功能。(不过,用户的安全设置或许会阻止你的脚本实例化客户端对象)

扩展函数包含在<msmsl:script>元素所定义的脚本块中。样式表可包含多个脚本块,各脚本块的操作相互独立。也就是说,如果在脚本块的内部执行,则无法调用在其他脚本块中定义的函数,除非该脚本块声明为具有同一命名空间和同一脚本语言。由于每个脚本块都可以使用自己的语言,因此脚本块的分析将遵照该语言分析器的语法规则进行。使用的语法对于所用的语言而言必须是正确的。例如,如果使用的是 C# 脚本块,则在该块中使用 XML 注释节点 <!-- an XML comment --> 是错误的,应该使用C#注释符"//"或者"/*…*/"。

下面的例子建立一个附带名字空间前缀"mycompany"的脚本块,脚本中包含一个"sum"的函数,该函数接受两个double类型参数,并计算它们的和,然后转换成字符串输出。随后,xsl元素<xsl:value-of>的select属性调用这个函数并输出结果。  

  1. <?xml version="1.0" encoding="utf-8" ?> 
  2. <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  3.                 xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
  4.                 xmlns:mycompany="http://mycompany.com/mynamespace" 
  5.                 version="1.0"> 
  6.   <msxsl:script language="c#" implements-prefix="mycompany"> 
  7.     private string sum(double a,double b) { 
  8.       return (a+b).ToString(); 
  9.     } 
  10.   </msxsl:script> 
  11.   <xsl:template match="/"> 
  12.     <xsl:value-of select="mycompany:sum(5.0,10.0)"/> 
  13.   </xsl:template> 
  14. </xsl:stylesheet> 

为演示效果,在<xsl:value-of select="mycompany:sum(5,10)" />中调用扩展函数sum时,硬性编码了两个double值5.0和10.0,实际中,参数取值应该来自于xml源文档或者通过自定义参数传入。

鉴于xml元素内容的特殊要求,即它不能直接包含"、'、<、>、&等字符以及所有非显示字符,而给定语言的运算符、标识符或分隔符恰好可能包含这些字符,它们有可能被错误地解释为XML。而将所有这些字符完全替换成对应的实体(标准实体和字符实体)引用将降低xml文件的可读性。所以,在使用 msxsl:script 元素时,强烈建议无论使用何种语言,都将脚本放置在 CDATA 节内。例如,下面的 XML 显示放置代码的 CDATA 节的模板。  

  1. <msxsl:script implements-prefix='myScript' language='c#'> 
  2.     <![CDATA[ 
  3.     <!--在这里放置代码--> 
  4.     ]]> 
  5. </msxsl:script> 

例如,下面的示例显示如何在脚本中使用逻辑 AND 运算符。

  1. <msxsl:script implements-prefix='myScript' language='c#'> 
  2.     public string book(string abc, string xyz) 
  3.     {  if ((abc== abc)&&(abc== xyz)) return bar+xyz; 
  4.         else return null; 
  5.     } 
  6. </msxsl:script> 

由于"&"符没有转义,因此这将引发异常。将文档作为 XML 加载,并且不对 msxsl:script 元素标记之间的文本运用任何特殊处理。

.Net中使用带扩展功能的Xslt样式表

.Net中的Xslt转换对象提供了对在Xslt文档中用脚本扩展元素来嵌入脚本语言的支持。XslTransform类专门为此提供实现。它包含的方法使用 Xslt样式表转换 Xml 数据为指定的输出。其中,用于载入Xslt转换文档的XslTransform..Load()方法接受包含嵌入脚本的样式表,实际执行转换的XslTransform.Transform()方法使用这个样式表将Xml源文档转换为指定的输出。在这里,源Xsl文档是否包含嵌入脚本并不影响程序代码的编写,你不需要为此额外添加代码。也就是说,在高级语言中编写程序代码时,包含嵌入脚本的Xsl文档与不包含嵌入脚本的Xsl文档使用一样的转换语句。

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

综合上面的知识,下面使用Visual Studio.Net SDK创建了一个控制台应用程序UseXsltScript,该程序调用包含嵌入脚本的trans.xsl转换文档,对data.xml源文档执行转换,并将结果输出到一个新的newxml.xml文件。该例中的Xslt嵌入脚本用来计算已知三角形底边及该边对应高度的情况下,计算此三角形的面积。  

  1. using System; 
  2. using System.Xml; 
  3. using System.Xml.Xsl; 
  4. using System.IO; 
  5. namespace MyCompanyUri.UseXsltScript 
  6.     class Xslt 
  7.     { 
  8.         private const string xmlfile = "../../data.xml";//xml源文档 
  9.         private const string xslfile = "../../trans.xsl";//xsl转换文档 
  10.         private const string newxml="../../outxml.xml";//转换后的xml文档 
  11.         public static void Main()  
  12.         { 
  13.             XmlDocument doc=new XmlDocument();//实例化xml文档对象 
  14.             doc.Load(xmlfile);//加载xml文档 
  15.             XslTransform xslt = new XslTransform();  
  16. //实例化XsltTransform转换类对象 
  17.             xslt.Load(xslfile);//加载xslt转换样式表 
  18.             FileStream myStream=new  
  19. FileStream(newxml,FileMode.OpenOrCreate);//以流方式打开文件 
  20.             XmlTextWriter writer = new  
  21. XmlTextWriter(myStream,null);//实例化xml编写器并提供控制台输出 
  22.             writer.Formatting = Formatting.Indented;//设置输出的缩进格式 
  23.             xslt.Transform(doc, null, writer);//转换xml文档并输出 
  24.             writer.Close(); 
  25.         } 
  26.     } 

xml源文件data.xml: 

  1. <?xml version="1.0" encoding="utf-8" ?> 
  2. <triangles> 
  3.     <triangle> 
  4.         <size> 
  5.             <width>2</width> 
  6.             <height>4</height> 
  7.         </size> 
  8.     </triangle> 
  9.     <triangle> 
  10.         <size> 
  11.             <width>13</width> 
  12.             <height>8</height> 
  13.         </size> 
  14.     </triangle> 
  15. </triangles> 

trans.xsl文件: 

  1. <?xml version="1.0" encoding="utf-8" ?> 
  2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  
  3. xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:myscript="urn:myns"> 
  4.     <msxsl:script language="C#" implements-prefix="myscript"> 
  5.      <![CDATA[ 
  6.      public double triangleArea(double width,double height){ 
  7.        double area = width*height/2;//面积公式:(底*高)/2 
  8.        return area;//返回三角形面积 
  9.      } 
  10.       ]]> 
  11.    </msxsl:script> 
  12.     <xsl:template match="//triangles"> 
  13.         <triangles> 
  14.             <xsl:for-each select="triangle/size"><!--选定size节点--> 
  15.                 <triangle> 
  16.                     <xsl:copy-of select="../size"  
  17. /><!--复制size节点 --> 
  18.                     <area> 
  19.                         <xsl:value-of  
  20. select="myscript:triangleArea(width,height)" /><!--调用函数--> 
  21.                     </area> 
  22.                 </triangle> 
  23.             </xsl:for-each> 
  24.         </triangles> 
  25.     </xsl:template> 
  26. </xsl:stylesheet> 

执行这个控制台程序,在应用程序目录的相应地方将生成outxml.xml文件。它将包含给定三角形的底边、高度尺寸及对应的面积。

另外,运行这个应用程序的时候你能够明显感觉到程序产生了短暂的延迟。这是因为在装入样式表处理嵌入式脚本之前,必须先装入c#编译器并运行该嵌入式c#脚本,这将花费2秒左右的时间。

需要注意的是:Xslt嵌入脚本中扩展函数的参数及函数返回值必须是 W3C XPath 类型之一,这些类型并不与.Net所支持的类型完全一致(关于这些W3C Xpath类型和.Net类型的对应情况请参见MSDN)。如果脚本函数使用其他的类型,或者,如果函数在样式表加载到 XslTransform 对象中时不进行编译,则将引发异常。 

设为首页 | 加入收藏 | 网学首页 | 原创论文 | 计算机原创
版权所有 网学网 [Myeducs.cn] 您电脑的分辨率是 像素
Copyright 2008-2020 myeducs.Cn www.myeducs.Cn All Rights Reserved 湘ICP备09003080号 常年法律顾问:王律师