System.Xml.Xsl命名空间包含.NET Framework用于支持XSL Transform的类。这个命名空间中的类可以和任何实现IXPathNavigable接口的存储器一起使用。在目前的.NET Framework中,包含XmlDocument、XmlDataDocument和 XPathDocument。与XPath一样,应使用最有效的存储器。如果计划创建一个定制存储器,例如文件系统,并进行一定的转换,就应在类中实现IXPathNavigable接口。
XSL建立在一个流拉模式(streaming pull mode)上。因此,可以把几个转换链接在一起。如果需要,甚至可以在转换之间应用一个定制阅读器,这样在设计时就会有很大的灵活性。
第一个示例获取books.xml文档,并使用XSLT文件book.xsl把它转换为一个简单的HTML文档,以进行显示(这段代码在XPathXSLSample3文件夹中),需要添加如下using语句:
using System.IO;
using System.Xml.Xsl;
using System.Xml.XPath;
下面是执行转换的代码:
private void button1_Click(object sender, System.EventArgs e)
{
//create the new XPathDocument
XPathDocument doc = new XPathDocument("..\\..\\..\\booksxpath.xml");
//create a new XslTransForm
XslTransform transForm = new XslTransform();
transForm.Load("..\\..\\..\\books.xsl");
//this FileStream will be our output
FileStream fs=new FileStream("..\\..\\..\\booklist.html",
FileMode.Create);
//Create the navigator
XPathNavigator nav = doc.CreateNavigator();
//Do the transform. The output file is created here
transForm.Transform(nav, null, fs);
}
这就是一个简单的转换。创建一个基于XPathDocument的对象和一个基于XslTransform的对象。把booksxpath.xml文件加载到XPathDocument上,把books.xsl文件加载到XslTransform上。
在本例中,再创建一个FileStream对象,把新HTML文档写入磁盘。如果这是一个ASP.NET应用程序,就可以使用TextWriter对象,把它传递给HttpResponse对象。如果要转换为另一个XML文档,就可以使用一个基于XmlWriter的对象。
准备好XPathDocument 和 XslTransform对象后,就在XPathDocument上创建XPathNavigator,并把XPathNavigator和Fliestream传送给XslTransForm对象的Transform方法。Transform()有几个重载方法,其参数是浏览器、XsltArgumentList (详见后面的讨论)、IO流和XmlResolver的组合。浏览器参数可以是XPathNavigator或执行IXPathNavigable接口的其他对象。IO流可以是基于TextWriter、Stream或XmlWriter的对象。XmlResolver处理安全性,打开数据源,返回数据或流。在.NET Framework 1.0中,XmlResolver参数不是必须的。TransForm方法的所有版本都受到非议,现在XmlResolver参数是必须的,但如果不需要XmlResolver的特性即安全性和凭证管理,可以把它设置为null。
books.xsl文档是一个很简单的样式表,如下所示:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
<title>Price List</title>
</head>
<body>
<table>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="bookstore">
<xsl:apply-templates select="book"/>
</xsl:template>
<xsl:template match="book">
<tr><td>
<xsl:value-of select="title"/>
</td><td>
<xsl:value-of select="price"/>
</td></tr>
</xsl:template>
</xsl:stylesheet>
前面提到了XsltArgumentList,这是把对象和方法绑定到命名空间上的一种方式。绑定好后,就可以在转换过程中调用该方法。下面的示例说明了它的具体工作方式(在XPathXSLSample4中)。将下面突出显示的代码添加到示例代码中:
private void button1_Click(object sender, System.EventArgs e)
{
//new XPathDocument
XPathDocument doc=new XPathDocument("..\\..\\..\\booksxpath.xml");
//new XslTransform
XslTransform transForm=new XslTransform();
transForm.Load("..\\..\\..\\booksarg.xsl");
//new XmlTextWriter since we are creating a new XML document
XmlWriter xw=new XmlTextWriter("..\\..\\..\\argSample.xml",null);
//create the XsltArgumentList and new BookUtils object
XsltArgumentList argBook=new XsltArgumentList();
BookUtils bu=new BookUtils();
//this tells the argumentlist about BookUtils
argBook.AddExtensionObject("urn:ProCSharp",bu);
//new XPathNavigator
XPathNavigator nav=doc.CreateNavigator();
//do the transform
transForm.Transform(nav,argBook,xw);
xw.Close();
}
//simple test class
public class BookUtils
{
public BookUtils(){}
public string ShowText()
{
return "This came from the ShowText method!";
}
}
下面是转换的结果。其结果已进行了格式化,以便于查看(argSample.xml):
<books>
<discbook>
<booktitle>The Autobiography of Benjamin Franklin</booktitle>
<showtext>This came from the ShowText method!</showtext>
</discbook>
<discbook>
<booktitle>The Confidence Man</booktitle>
<showtext>This came from the ShowText method!</showtext>
</discbook>
<discbook>
<booktitle>The Gorgias</booktitle>
<showtext>This came from the ShowText method!</showtext>
</discbook>
<discbook>
<booktitle>The Great Cookie Caper</booktitle>
<showtext>This came from the ShowText method!</showtext>
</discbook>
<discbook>
<booktitle>A Really Great Book</booktitle>
<showtext>This came from the ShowText method!</showtext>
</discbook>
</books>
在本例中,我们定义一个新类BookUtils。在这个类中有一个不起作用的方法,它返回字符串This came from the ShowText method!。在button1_Click事件中,像以前一样创建XPathDocument 和 XslTransform,但这次有一个不同。这次我们创建一个XML文档,所以使用XMLWriter来代替以前的FileStream。下一个变化如下所示:
XsltArgumentList argBook=new XsltArgumentList();
BookUtils bu=new BookUtils();
argBook.AddExtensionObject("urn:ProCSharp",bu);
这段代码创建了XsltArgumentList对象。接着创建BookUtils对象的一个实例,在调用AddExtensionObject方法时,其参数是扩展的命名空间和要调用方法的对象。在调用Transform时,其参数是XsltArgumentList (argBook)、前面创建的XPathNavigator和XmlWriter对象。
下面是booksarg.xsl文档(基于books.xsl):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:bookUtil="urn:ProCSharp">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:element FTEL="books">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="bookstore">
<xsl:apply-templates select="book"/>
</xsl:template>
<xsl:template match="book">
<xsl:element FTEL="discbook">
<xsl:element FTEL="booktitle">
<xsl:value-of select="title"/>
</xsl:element>
<xsl:element FTEL="showtext">
<xsl:value-of select="bookUtil:ShowText()"/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
两行重要的代码已突出显示。首先,在给XsltArgumentList添加对象时,添加了前面创建的命名空间。然后,在调用方法时,使用标准的XSLT命名空间前缀语法。
另一种方式是使用XSLT脚本。可以在该样式表中包含C#、VB和 JavaScript代码。最重要的是在Transform.Load调用中编译该脚本,这与目前的非.NET实现不同。这样就可以执行已经编译好的脚本,与ASP.NET的工作方式相同。
下面对前面的XSLT文件也进行这样的操作。首先给样式表添加脚本,在booksscript.xsl中进行的修改如下所示:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://wrox.com">
<msxsl:script language="C#" implements-prefix="user">
string ShowText()
{
return "This came from the ShowText method!";
}
</msxsl:script>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:element FTEL="books">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="bookstore">
<xsl:apply-templates select="book"/>
</xsl:template>
<xsl:template match="book">
<xsl:element FTEL="discbook">
<xsl:element FTEL="booktitle">
<xsl:value-of select="title"/>
</xsl:element>
<xsl:element FTEL="showtext">
<xsl:value-of select="user:ShowText()"/>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
其中的改变已突出显示。设置脚本的命名空间,添加代码(可以从VS.NET IDE中复制和粘贴),在样式表上执行调用。输出结果与前面示例的相同。
总之,在进行转换时,一定要记住使用正确的XML数据存储:如果不需要编辑功能,就使用XPathDocument;如果要从ADO.NET中获得数据,就使用XmlDataDocument;如果需要编辑数据,就使用XmlDocument。其他过程都相同。