XSLT 2.0 编程基础






4.87/5 (10投票s)
本文面向初学者介绍 XSLT 编程。
目录
- 引言
- 必备组件
- 设置环境
- XSLT 基础知识
- 显示 XML 数据
- 使用 XSL 模板
- XSL 变量和参数
- 排序和过滤(
xsl:key
元素和generate-id()
函数) - 数据分组
- 分页
- XSLT 2.0 函数
- 练习
- 关注点
- 结论
引言
XSLT 代表 XSL Transformations(XSL 转换)。XSL 广为人知,即 Extensible Stylesheet Language(可扩展样式表语言),用于 XML 文档。XSLT 是一种语言,用于描述可应用于一组 XML 文档以生成一组新的转换后的 HTML 文档的转换。
下图显示了 XSLT 处理器的流程。
从上图可以清楚地看出,XSLT 处理器将 XML 文件作为输入,并根据 XSLT 指令将其处理为 HTML 文档。
在本文中,我们将通过一些代码片段来了解使用 Saxon API for .NET 的最新 XSLT 编程版本。
必备组件
为了执行代码,我们需要具备以下条件
- .NET Framework
- Visual Studio
- 适用于 .NET 的 Saxon.dll
环境设置
为了编译 XSLT 2.0 代码,我们应该使用 Saxon .NET 库,该库可在此处获取。一旦 Saxon .NET 库可用,我们可以通过将其作为引用添加到项目中来将其包含在我们的项目中。以下方法将 XML、XSLT 文件路径名和 xsl-param
值作为参数,并将解析后的 XML 值以 HTML 格式作为字符串返回。我们可以在 Literal
控件中显示获得的 HTML 输出。
public static string transformXml(string sourceUri, string xsltUri, double CurrentPage,string category)
{
Processor processor = new Processor();
XdmNode input = processor.NewDocumentBuilder().Build(new Uri(sourceUri));
XsltTransformer transformer = processor.NewXsltCompiler().Compile(new Uri(xsltUri)).Load();
transformer.InitialContextNode = input;
transformer.SetParameter(new QName("", "", "currentPage"), new XdmAtomicValue(CurrentPage));
transformer.SetParameter(new QName("", "", "category"), new XdmAtomicValue(category));
transformer.BaseOutputUri = new Uri(xsltUri);
Serializer serializer = new Serializer();
StringWriter sw = new StringWriter();
serializer.SetOutputWriter(sw);
transformer.Run(serializer);
return sw.ToString();
}
XSLT 基础
XSLT 包含以下元素
xsl:template | xsl:param |
xsl:calltemplate | xsl:sort |
xsl:choose | xsl:attribute |
xsl:for-each-group | xsl:valueof |
XSL 元素的完整列表参考可在此处获取。
正如我们已经看到了一些常用的 XSLT 元素列表,现在我们将尝试执行一些最常用的操作。
显示 XML 数据
xsl:foreach
元素有助于循环 XML 文件的所有元素并显示它们。在下面的示例中,我们将使用 xsl:foreach
元素以表格格式显示数据。
<xsl:template match ="books">
<table>
<tr>
<th align ="left">S.No</th>
<th align ="left">Title</th>
<th align ="left">Author</th>
<th align ="left">Price</th>
<th align ="left">Category</th>
</tr>
<xsl:for-each select ="book">
<tr>
<td>
<xsl:number/>
</td>
<td>
<xsl:value-of select ="title"/>
</td>
<td>
<xsl:value-of select ="author"/>
</td>
<td>
<xsl:value-of select ="price"/>
</td>
<td>
<xsl:value-of select ="@category"/>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
string sourceUri = Server.MapPath("books.xml");
string xsltUri = Server.MapPath("code1.xslt");
string text = SaxonDemo.transformXml(sourceUri, xsltUri);
Literal1.Text = text;
- 使用 Visual Studio 创建一个新的空 Web 项目。
- 将可随本文下载的 XML 文件添加到项目中。
- 添加一个类文件,并将代码片段 1 复制到类文件中,并添加所需的引用库。
- 向您的项目添加一个新的 XSLT 文件并复制以下代码
- 暂时排除代码片段 1 中的参数。
- 向项目中添加一个新的 Web (.aspx) 页面,并将一个
Literal
控件拖到页面上。 - 将以下代码添加到
Page_Load
函数
对下面描述的所有其他示例重复上述步骤。
使用 XSL 模板
XSL 模板类似于一般编程语言中的函数/方法。XSL 模板用于定义可在整个程序中重复使用的代码。XSL 模板使用 xsl:variable
元素来声明和存储变量,就像传统编程一样。xsl:param
元素用于 xsl:template
中,以便将参数传递给模板。
为了了解如何使用 xsl:template
定义一段代码,我们将对代码片段 2 进行少量修改。我们将 xsl:foreach
元素代码单独声明在一个名为“results
”的模板中,然后我们将使用 xsl:call
模板元素调用该模板,如下所示
<xsl:template name ="results">
<xsl:for-each select ="book">
<tr>
<td>
<xsl:number/>
</td>
<td>
<xsl:value-of select ="title"/>
</td>
<td>
<xsl:value-of select ="author"/>
</td>
<td>
<xsl:value-of select ="price"/>
</td>
<td>
<xsl:value-of select ="@category"/>
</td>
</tr>
</xsl:for-each>
</xsl:template>
<xsl:template match ="books">
<table>
<tr>
<th align ="left">S.No</th>
<th align ="left">Title</th>
<th align ="left">Author</th>
<th align ="left">Price</th>
<th align ="left">Category</th>
</tr>
<xsl:call-template name ="results"></xsl:call-template>
</table>
</xsl:template>
- 创建一个名为
results
的模板。 - 使用
xsl:calltemplate
元素调用上述模板。
XSL 变量和参数
xsl:variable
元素用于存储可在程序中使用的数据。符号“$
”用于访问声明的变量。以下代码显示了变量的用法
<xsl:variable name ="totalRecords">
<xsl:for-each select ="/">
<xsl:value-of select ="count(books/book)"/>
</xsl:for-each>
</xsl:variable>
<tr>
<td colspan="5">
<b>Total No of Record(s):<xsl:value-of select ="$totalRecords"/>
</b>
</td>
</tr>
- 声明一个变量。
- 访问变量。
xsl:parameter
元素用于将参数传递给 xsl:template
。xsl:call
template 元素用于调用带参数的 xls:template
。为了演示 xsl:parameter
元素,我们将使用另一种方法通过 XSL 参数显示记录总数。
<xsl:template name ="results">
<xsl:param name ="ttlrds"/>
!!-------- previously used foreach loop code goes here-------------!!
<tr>
<td colspan="5">
<b>
Total No of Record(s):<xsl:value-of select ="$ttlrds"/>
</b>
</td>
</tr>
</xsl:template>
<xsl:template match ="books">
<xsl:variable name ="totalRecords">
<xsl:for-each select ="/">
<xsl:value-of select ="count(books/book)"/>
</xsl:for-each>
</xsl:variable>
<table>
!!...Table heading code from the above code snippet goes here……!!
<xsl:call-template name ="results">
<xsl:with-param name ="ttlrds" select ="$totalRecords">
</xsl:with-param>
</xsl:call-template>
</table>
</xsl:template>
- 使用
xsl:param
元素定义一个带参数的模板。 - 使用
xsl:call
template 和xsl:with
param 元素调用模板。
条件(If 和 When)元素
我们可以通过使用 xsl:if
或 xsl:when
对 XML 文件中的元素应用条件。以下代码分别显示了两者的示例。
xsl:if 示例
<xsl:variable name ="a" select ="24" />
<xsl:if test ="$a<5">
!!! The value of a (<xsl:value-of select ="$a"/>) is less than 5.
</xsl:if>
xsl:choose 示例
<xsl:choose>
<xsl:when test ="$a>5">
The value of a (<xsl:value-of select ="$a"/>) is greater than 5.
</xsl:when>
<xsl:otherwise>
== The value of a (<xsl:value-of select ="$a"/>) is less than 5.
</xsl:otherwise>
</xsl:choose>
</xsl:template>
排序和过滤(xsl:key 元素和 generate-id() 函数)
xsl:sort
元素用于对值进行排序。以下语法显示了 XSL 中排序的用法
<xsl:sort order ="ascending" select="author"/>
为了理解如何在 XSL 编程中使用过滤,我们将通过以下演示,其中我们首先将所有不同的值添加到下拉列表中,然后我们将利用这些值来过滤记录。
通过使用 xsl:key
元素和 generate-id()
函数,我们可以获得不同的值,如下所示。下面的代码片段从 XML 文件中提取不同的作者值,并将这些值绑定到下拉列表。
<xsl:key name="athr" match="/books/book/author/text()" use="." />
<select onchange ="getvalue(this.value)">
<option>==select==</option>
<xsl:for-each select="/books/book/author/text()[generate-id()=generate-id(key('athr',.)[1])]">
<option>
<xsl:value-of select="."/>
</option>
</xsl:for-each>
</select>
function getvalue(va){
var txtval = document.getElementById('txtid');
txtval.value = va;
form1.submit();
}
string category = string.Empty;
category = txtid.Text;
txtid.Text = string.Empty;
string text = SaxonDemo.transformXml(sourceUri, xsltUri,currentPage, category);
Literal1.Text = text;
<xsl:param name="category" />
<xsl:for-each select ="books/book[@category=$category]">
<xsl:call-template name ="results"></xsl:call-template>
</xsl:for-each>
- 使用 XSLT 获取不同的值
- 从 JavaScript 和 C# 传递筛选值
- 根据筛选值获取记录
数据分组
XSLT 2.0 引入了 xsl:for-each-group
元素,用于根据给定列对记录进行分组。
<xsl:for-each-group select="book" group-by="@category">
<h2>
<xsl:text>Category:</xsl:text>:<xsl:value-of select="current-grouping-key()"/>
</h2>
<xsl:for-each-group select="current-group()" group-by="@Genre">
<h2>
<xsl:text>Genre:</xsl:text>:<xsl:value-of select="current-grouping-key()"/>
</h2>
<xsl:for-each select="current-group()">
<table>
<xsl:call-template name ="results"></xsl:call-template>
</table>
</xsl:for-each>
</xsl:for-each-group>
</xsl:for-each-group>
上述代码可以重复,以对多级列进行分组。
分页
正如我们在 ASP.NET GridView
中进行分页一样,此处显示在 XSL 中的记录也可以获得类似的结果。
<xsl:variable name ="totalRecords">
<xsl:for-each select ="/">
<xsl:value-of select ="count(books/book)"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name ="recordsPerPage">
<xsl:value-of select ="8"/>
</xsl:variable>
<xsl:param name ="pageCount" select ="round($totalRecords div $recordsPerPage)" />
<xsl:param name="currentPage"/>
<xsl:param name="category" />
<xsl:if test ="$currentPage>=1 and $currentPage < $pageCount">
<td>
<a>
<xsl:attribute name="href">
Default.aspx?page=<xsl:value-of select="number($currentPage)+1"/>
</xsl:attribute>
Next>
<xsl:if test ="$currentPage>1 and $currentPage <= $pageCount">
<td>
<a>
<xsl:attribute name="href">
Default.aspx?page=<xsl:value-of select="number($currentPage)-1"/>
</xsl:attribute>
Previous<<
</a>
</td>
</xsl:if>
<td colspan ="3" align ="center">
<h3>
Page <xsl:value-of select ="$currentPage"/> of <xsl:value-of select ="$pageCount"/>
</h3>
</td>
<xsl:template name ="results">
<xsl:for-each select ="book">
<xsl:if test ="position() > number(($currentPage*$recordsPerPage)-$recordsPerPage)
and position() <= number($currentPage*$recordsPerPage)">
!!!!!!------ Display the record(s) --------- !!!!!
</xsl:if>
</xsl:for-each>
</xsl:template>
- 最初,定义了以下变量和参数
- 检查下一组要显示的记录的条件,并通过将
href
属性添加到 HTML 的锚标签来定义“下一页”按钮的代码,如下所示 - 同样,对于“上一页”按钮,使用以下代码
- 页码和记录总数显示如下
- 最后通过检查以下条件显示结果
以下代码用于使用 C# 代码传递参数
string text = SaxonDemo.transformXml(sourceUri, xsltUri, currentPage, category);
Literal1.Text = text;
XSLT 2.0 函数
XSLT 2.0 带有大量内置函数,涉及主机名、日期、字符串等不同方面。我们可以在此处找到完整的函数列表。
使用内置函数的基本示例如下所示
<xsl:value-of select ="substring('saichandras','4')"/>
<br/>
<xsl:value-of select ="string-join(('20','04','1989'),'-')"/>
更多示例可在此处获取。
练习
练习 1
一个用于查找给定数字阶乘的 XSLT 程序。以下 XSLT 模板用于查找给定数字的阶乘。
<xsl:template name="factorial">
<xsl:param name="n" select="1"/>
<xsl:variable name="sum">
<xsl:if test="$n = 1"> 1 </xsl:if>
<xsl:if test="$n != 1">
<xsl:call-template name="factorial">
<xsl:with-param name="n" select="$n - 1"/>
</xsl:call-template>
</xsl:if>
</xsl:variable>
<xsl:value-of select="$sum * $n"/>
</xsl:template>
调用此模板
<xsl:call-template name ="factorial">
<xsl:with-param name ="n" select="5">
</xsl:with-param>
</xsl:call-template>
此链接提供了更多 XSLT 编程的实践示例。
关注点
在本教程中,我们直接使用原始 XML 文件作为输入,但大多数时候,如果我们需要从数据库表中获取数据,我们可以从 .NET 的 DataSet
类获取 XML。以下代码描述了这一点
string xsltUri = Server.MapPath("code1.xslt");
string query = "select * from books";
SqlConnection con = new SqlConnection("data source =.; intial catalog=books; integrated security=true;");
DataSet ds = new DataSet("books");
SqlDataAdapter da = new SqlDataAdapter(query, con);
da.Fill(ds);
MemoryStream ms = new MemoryStream();
ds.WriteXml(ms);
string text = SaxonDemo.transformXml(ms, xsltUri);
Literal1.Text = text;
结论
在本文中,我尝试提供一些关于如何使用 XSLT 元素进行编程的基本示例。还有很多文章更详细地解释了 XSLT。以下列表提供了一些进一步阅读的链接