XML (转换)
XSL(Extensible Stylesheet Language,可扩展样式表语言)是一种用于创建样式表的基于 XML 的语言。样式表(转换)是特殊的文档,可以在 XSLT 处理器的帮助下把 XML 文档转换成其它文档。(不要和 CSS 混淆,CSS 是用来格式化 HTML 的标准)。
基本的样式表
XSL 是一个复杂的标准,事实上,它可以被看做是一个真正的语言,因为它有逻辑、循环结构等。
执行任何转换前,需要创建一个定义如何应用转换的 XSL 样式表。把 DVD 列表转换为 HTML 时,将用到下面所示的简单样式表:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="DvdList/DVD" />
</body>
</html>
</xsl:template>
<xsl:template match="DVD">
<hr />
<h3>
<u>
<xsl:value-of select="Title"/>
</u>
</h3>
<b>Price: </b>
<xsl:value-of select="Price"/>
<br />
<b>Director: </b>
<xsl:value-of select="Director"/>
<br />
<xsl:apply-templates select="Starring" />
</xsl:template>
<xsl:template match="Starring">
<b>Starring</b>
<br />
<xsl:apply-templates select="Star" />
</xsl:template>
<xsl:template match="Star">
<li>
<xsl:value-of select="."/>
</li>
</xsl:template>
</xsl:stylesheet>
所有的 XSL 文件里都有一个根元素 <stylesheet>,<stylesheet>元素可包括一个或多个模版(这个示例有 4 个)。第一个<template>元素匹配根元素,找到它后,它开始输出 HTML 页面所必需的标签,接着它使用 <apply-templates> 命令分解并处理所有 <DVD> 元素,它们是 <DvdList>的子元素,如下所示:
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="DvdList/DVD" />
</body>
</html>
</xsl:template>
每匹配一个 <DVD> 标签,就添加一条水平线并创建一个标题。<Title>、<Price>、<Director>标签中的信息由 <value-of> 命令解析并写到页面上。
<xsl:template match="DVD">
<hr /><h3><u><xsl:value-of select="Title"/></u></h3>
<b>Price: </b><xsl:value-of select="Price"/><br />
<b>Director: </b><xsl:value-of select="Director"/><br />
<xsl:apply-templates select="Starring" />
</xsl:template>
使用 XslCompiledTransform
使用样式表以及 XslCompiledTransform 类(System.Xml.Xsl 命名空间中)可以把 DVD 列表转换为格式化的 HTML 。下面是执行转换的代码,同时把结果保存到一个新的文件里:
protected void Page_Load(object sender, EventArgs e)
{
string xslFile = Server.MapPath("DvdList.xslt");
string xmlFile = Server.MapPath("DvdList.xml");
string htmlFile = Server.MapPath("DvdList.htm");
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(xslFile);
transform.Transform(xmlFile, htmlFile);
}
在一个动态的 Web 应用程序里,你会希望转换 XML 文件后直接返回结果代码,而不是生成一个 HTML 文件。要做到这点,需要为源 XML 文件创建 XPathNavigator ,然后可以把这个 XPathNavigator 传递给 Transform()方法,并获取任意流对象中的结果:
protected void Page_Load(object sender, EventArgs e)
{
// Create an XPathNavigator.
string xmlFile = Server.MapPath("DvdList.xml");
XPathDocument xdoc = new XPathDocument(new XmlTextReader(xmlFile));
XPathNavigator xnav = xdoc.CreateNavigator();
// Transform the XML.
MemoryStream ms = new MemoryStream();
XsltArgumentList args = new XsltArgumentList();
XslCompiledTransform transform = new XslCompiledTransform();
string xslFile = Server.MapPath("DvdList.xslt");
transform.Load(xslFile);
transform.Transform(xnav, args, ms);
// 一旦拥有了某个 MemoryStream 中的结果,就可以创建 StreamReader 来获取
StreamReader r = new StreamReader(ms);
ms.Position = 0;
Response.Write(r.ReadToEnd());
r.Close();
}
使用 XML 控件
有时候你可能希望把带有其他内容的转换后的 HTML 输出和 Web 控件组合在一起,XML 控件在页面独立的部分显示 XSL 转换后的结果:
<asp:Xml ID="Xml1" runat="server" DocumentSource="DvdList.xml"
TransformSource="DvdList.xslt"></asp:Xml>
这个示例最好的一点是只需设置 2 个属性而不需要手工书写任何代码。
不必为了使用 XML 控件而使用独立的文件。
你也可以在编码中把 XmlDocument 对象赋给 Document 属性,或者给 DocumentContent 属性赋一个包含 XML 内容的字符串,而不是使用 DocumentSource 属性。类似的,你可以给 Transform 属性赋一个 XslTransform 对象值来提供 XSLT 信息。
如果需要编程来支持 XML 和 XSLT 数据(从数据库记录中抽取数据),这些技术将非常有用。
使用 LINQ to XML 转换 XML
XSL 并不是改变 XML 格式的唯一方式(过去它是唯一实际可行的办法),但今天,LINQ to XML 提供了一个富有竞争力的选择。要使用 LINQ to XML 进行转换,你需要一个运用投影的 LINQ 表达式。技巧在于投影必须返回一个 XElement 而不是匿名类型。
string xmlFile = Server.MapPath("DvdList.xml");
XDocument doc = XDocument.Load(xmlFile);
XDocument newDoc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("Movies",
from DVD in doc.Descendants("DVD")
where (int)DVD.Attribute("ID") < 3
select new XElement[]
{
new XElement ("Moive",
new XAttribute("name", (string)DVD.Element("Title")),
DVD.Descendants("Star")
)
}
)
);
string newFile = Server.MapPath("MovieList.xml");
newDoc.Save(newFile);
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Movies>
<Moive name="The Matrix">
<Star>Keanu Reeves</Star>
<Star>Laurence Fishburne</Star>
</Moive>
<Moive name="Forrest Gump">
<Star>Tom Hanks</Star>
<Star>Robin Wright</Star>
</Moive>
</Movies>
基于 LINQ 转换的语法通常要比使用 XSL 样式表的转换更容易理解,并且更加精确。你也可以很方便的替换为另一个 IEnumable<T>的集合,包括 LINQ to Entities 获得的结果集,然后随意打包成另一种格式的 XML 文档。