什么网站可以做高三英语试题,百度h5下载,wordpress门户主题破解版,公司域名查询官方网站本文假设您熟悉 Visual Basic .NET 下载本文的代码#xff1a; XPathandXSLT.exe (166KB) 摘要 XPath 是一种正在兴起的通用查询语言。通过 XPath#xff0c;可以在基于 XML 的数据源中识别和处理一组相关的节点。XPath 提供了一个基础结构#xff0c;它是 .NET Framewo…本文假设您熟悉 Visual Basic .NET 下载本文的代码 XPathandXSLT.exe (166KB) 摘要 XPath 是一种正在兴起的通用查询语言。通过 XPath可以在基于 XML 的数据源中识别和处理一组相关的节点。XPath 提供了一个基础结构它是 .NET Framework 中的 XML 支持的组成部分。XPath 导航模型甚至用在 XSLT 处理程序的内部。在本文中作者考察了 XPath 导航器和 XSLT 处理程序的实现细节并且包含了一些实际的示例例如异步转换、排序节点集和 ASP.NET 服务器端转换。 XML 的主要优点之一是它使您可以用标记和属性标记文本的某些部分。您在文本内部标记数据的原因是您计划以后检索它。那么如何完成这一工作呢您可以使用 XPath。 虽 然 XPath 不具有基于 XML 的语法但它是为了以简洁的、相对简单的方式对 XML 文档的某些部分进行寻址而定义的语言。更为重要的是XPath 定义了一种常见的语法以便您可以从实现了 XML 文档对象模型 (DOM) 的类内部以及从 XSLT 中检索节点。 在 Microsoft®.NET Framework 中通过在 System.Xml.XPath 命名空间中定义的类对 XPath 查询语言提供了完整的支持。.NET Framework 对 XPath 的实现基于语言分析程序和评估引擎。XPath 查询的整体体系结构与数据库查询类似。就像 SQL 命令一样需要准备 XPath 表达式并将它们提交给运行库引擎以进行评估。查询是针对 XML 数据源加以分析和执行的。接下来您将取回一些表示查询的结果集的信息。XPath 表达式可以返回节点集即有序的节点集合、布尔值、数字或字符串。 在本文中我将说明 XPath 如何与 .NET Framework 中的 XmlDocument 类和 XSLT 集成。我还将对 XPathNavigator 类.NET Framework 使用它来遍历 XML 文档进行深入的剖析。 XPath 表达式 XPath 是一种专门设计的查询语言用于对 XML 文档的元素和文本进行寻址。XPath 表示法在本质上是声明性的。任何有效的表达式都会使用强调节点之间层次关系的表示法来声明节点模式。与文件系统路径类似XPath 表达式从根XPath 术语中的轴前进至源文档中的特定节点集或值。然而它与文件系统的相似性并不仅限于此。XPath 表达式总是在节点的上下文中求值。上下文节点由应用程序指定并且代表查询的起点。它与当前目录的概念没有太大区别。 XPath 查询的上下文包括但不限于上下文节点和上下文节点集。上下文节点集是查询所处理的节点的整个集合。通常它是实际返回到应用程序的节点集的超集。 XPath 上下文还包含位置和命名空间信息、变量绑定和一个可供应用程序扩展的标准函数库。XPath 分析程序的任何实现都提供了一个用于对表达式进行求值的函数库。扩展函数被定义在特定于供应商的 XPath 实现中但是也可以由专用的和基于 XPath 的编程 API例如XSL 转换和 XPointer提供。XPath 表达式通常会返回节点集但是布尔值、字符串、数字和其他类型也受到支持。 最常用的 XPath 表达式类型是位置路径。位置路径是一个看起来与文件系统路径非常类似的表达式它既可以是绝对路径也可以是相对于上下文节点的相对路径。绝对位置路径以正斜杠开始。如图 1 中所示完全限定位置路径由三部分组成轴、节点测试以及一个或多个谓词。轴信息定义表达式的初始上下文节点集而节点测试是标识该节点集中路径的一系列节点名称。谓词是一个逻辑表达式它定义了用于筛选当前节点集的条件。 图 1 位置路径 XPath 表达式可以包含任何数量的谓词。如果没有指定任何谓词则在查询中返回该上下文节点的所有子节点。否则使用简捷的 AND 运算符将用各种谓词设置的条件逻辑地串联在一起。请注意谓词按照它们出现的顺序进行处理以便下一个谓词对上一个谓词生成的节点集起作用。 在 进行处理时XPath 表达式在名为位置步骤的子表达式中被标记化并且每个表达式都分别被计算。XPath 处理程序以迭代方式传递在上一步中生成的子表达式和上下文节点集。它返回一个可能缩小的节点集以便用作下一个子表达式的输入参数。在该过程中上下文节 点、位置和大小都可能变化而变量和函数引用以及命名空间声明保持不变。每个位置步骤实际上都是一个位置路径因此可以根据需要以缩写形式或完全限定形 式来表示。位置步骤由正斜杠分隔。 在 .NET Framework 中可以通过 XmlNode 类在 XmlDocument 类中公开的方法或者通过 XPathNavigator 类使用 XPath 表达式。 XPath 导航器 在 .NET Framework 中XmlDocument 类代表由 W3C 批准的标准 XML DOMDOM 级别 2 标准。在从 XmlDocument 中到达的每个子节点上都实现了几个搜索方法。XmlNode 类提供了 SelectNodes 和 SelectSingleNode 方法它们使用 XPath 表达式在文档中搜索节点。这些方法几乎与基于 COM 的 MSXML 库中具有类似名称的方法完全相同。SelectNodes 返回一系列对象而 SelectSingleNode 只返回第一个匹配搜索条件的对象。以下是使用 SelectNodes 的方法 Dim doc As XmlDocument New XmlDocument()doc.Load(fileName)Dim nodes As XmlNodeListnodes doc.SelectNodes(queryString) SelectSingleNode 方法与 SelectNodes 的不同之处在于它返回单个 XmlNode 对象。稍后我将详细讨论这些方法。 对 XPath 表达式的 XmlDocument 支持具有两个目标。它使从 MSXML COM 代码到 .NET Framework 的转换变得顺畅同时提供了一种在内存映射 XML 文档中搜索节点的内置机制。然而XmlDocument 查询 API 是简单的高级别包装。用于处理 XPath 表达式的核心 .NET Framework API 是围绕 XPathNavigator 类生成的。导航器是一个 XPath 处理程序它在任何公开 IXPathNavigable 接口的 XML 数据存储区之上工作。导航器通过 XPathNavigator 类中定义的接口呈现它使用 Select 方法分析和执行表达式。与 XmlDocument 方法不同导航器接受以纯文本形式提供的以及通过预编译对象提供的表达式。可以从 XmlDocument 类或 XPathDocument 类中以编程方式访问 XPathNavigator 对象。图 2 说明了两种访问 .NET Framework 中的 XPath 函数的方式。 图 2 访问 XPath 函数 以下代码片段显示了如何根据 XML 文档创建 XPathNavigator 以及如何执行 XPath 查询 Dim doc As XPathDocumentDim nav As XPathNavigatorDim iterator As XPathNodeIteratordoc New XPathDocument(fileName)nav doc.CreateNavigator()iterator nav.Select(queryString)While iterator.MoveNext() nav points to the node subtreeEnd While 导航器返回一个 XPath 迭代器对象。迭代器只是用来在返回的节点集中移动的专用枚举器对象。稍后我将讨论迭代器。 文档、导航器和读取器 在 .NET Framework 出现之前处理 XML 文件涉及到处理按照 SAX 或 XmlDocument 规范呈现的文档。 XPath 处理程序它是分析和执行 XPath 查询的引擎是在 XPathNavigator 类的内部生成的。如图 2 所示XPath 计算总是被委托给导航器而不管高级别调用方 API 是哪个。导航器在特定的数据存储区通常是 XPathDocument 类的实例之上工作。只要数据存储区类实现了如下所示的 IXPathNavigable 接口则也可以使用其他数据存储区 public interface IXPathNavigable { XPathNavigator CreateNavigator();} 除了 XPathDocument 类以外数据存储区的示例还包括 XmlDocument 和 XmlDataDocument。 数 据存储区负责提供导航器以探索内存中的 XML 内容。XPathNavigator 实现总是特定于存储区并且通过从 XPathNavigator 抽象类继承生成。尽管实际上您总是通过 XPathNavigator 的常见引用类型来编写导航器但每个数据存储区类都具有它自己的导航器对象。它们是内部的未记录的类无法以编程方式访问并且通常以相当不同的方式实 现。图 3 列出了 .NET Framework 中定义的三个 XPath 数据存储区所使用的真实导航器类。特定于文档的导航器利用文档类的内部布局以便提供导航 API。 XPathDocument 类为 XML 文档提供高度优化的、只读的内存中存储区。该类是专门设计以实现 XPath 数据模型的它没有为节点提供任何标识。它只是创建一个基础的节点引用树以便让导航器能够快速和有效地操作。XPathDocument 类的内部体系结构看起来像是节点引用链表。节点是通过一个代表 XmlNode 类的小型子集的内部类 (XPathNode) 来管理的参见图 2。 与 XPathDocument 相比XmlDocument 类提供了对基础 XML 文档的节点的读写访问。此外还可以分别访问每个节点。 XmlDocument 类还提供了创建导航器对象的能力如下所示 Dim doc As XmlDocument New XmlDocument()doc.Load(fileName)Dim nav As XPathNavigator doc.CreateNavigator() XmlDocument 的导航器类实现了 IHasXmlNode 接口。该接口定义了一个方法即 GetNode public interface IHasXmlNode {XmlNode GetNode();} 使用该方法调用方可以基于 XPathNavigator 的位置访问和询问 XmlDocument 中当前选择的节点。无法为基于 XPathDocument 的导航器实现该功能原因仅仅在于它不像 XmlDocument 类那样通过 XmlNode 类公开内部结构。这是设计使然。XPathDocument 最大限度地减小了内存足迹并且不提供节点标识。 因为 GetNode 方法是在 XmlDocument 上的 XPathNavigator 类上实现的所以调用方可以通过类型转换来利用它如以下代码片段所示 Dim doc As XmlDocument New XmlDocument()doc.Load(fileName)Dim nav As XPathNavigator doc.CreateNavigator()Dim i As XPathNodeIterator nav.Select(query)Dim node As XmlNode CType(i.Current, IHasXmlNode).GetNode() 此时调用方程序已经获得了对该节点的完全访问权限并且可以任意读取和更新它。 最 后XmlDataDocument 类是 XmlDocument 的扩展其目标是允许通过 XML 操作关系数据集。这是一个简洁的示例它说明了 .NET Framework 导航 API 可以应用于基于 XML 的数据以及类似于 XML数据的结构类似于 XML但不是 XML的数据这样一个事实。 如果您查看 XPath 导航器的 MSDN® 文档则将看到导航器以类似于游标的方式向前和向后从基于 XML 的数据存储区中读取数据并且提供对基础数据的只读访问。此外它保持有关当前节点的信息并且使用多种移动方法推进内部指针。当导航器定位于给定的节点 时它的所有属性都将反映该节点的值。当然这类似于 XML 读取器我在 MSDN Magazine 的 2003 年 5 月刊的一篇文章中对它进行了讨论。那么导航器和读取器之间有什么区别呢 导 航器和读取器是不同的东西。读取器类似于水龙带游标它提供基本的只读、只进移动。导航器也是只读的但是它们提供了一组丰富得多的移动方法包括向前和 向后选项。导航器还提供了多个选择方法以对搜索进行微调。读取器是更低级别的工具可以用来读取基于 XML 或类似于 XML 的数据以及生成内存中的数据结构。XML 读取器可以用来生成导航器所依赖的内存中数据结构。 查询节点 假设您需要在基 于 .NET Framework 的应用程序中实现 XPath 查询。是应当使用 XPath 导航器还是最好坚持使用 XmlDocument 的节点接口呢XmlNode 的 SelectNodes 方法在内部使用导航器对象来检索匹配节点列表。随后使用导航器的 Select 方法的返回值以便初始化一个类型为 XPathNodeList它定义在 System.Xml.XPath 命名空间中的内部节点列表对象。正像您可能已经猜到的那样该类从已记录的 XmlNodeList 类继承。此外与 SelectNodes 不同的是导航器可以完全利用已编译的表达式。 SelectNodes 方法总是以纯文本形式接受 XPath 表达式。字符串随后被逐字地传递给导航器。只有在一种情况下基础导航器才会收到已编译的表达式。如果您使用处理命名空间信息的 SelectNodes 方法重载则会首先编译 XPath 表达式然后将其传递给处理程序。重载方法的原型如下所示 Function SelectNodes( _ xpathExpr As String, _ nsm As XmlNamespaceManager) _As XmlNodeList 当您在会话中频繁重用该表达式时使用已编译表达式的优点变得非常明显并且它们具有命名空间识别功能。XmlNamespaceManager 类允许用户指定要绑定的命名空间的前缀。 SelectSingleNode 方法是 SelectNodes 的特例它只返回所返回节点集中的第一个元素。遗憾的是直到现在SelectSingleNode 的实现也不是特别有效。如果您只需要找到第一个匹配节点则调用 SelectSingleNode 或 SelectNodes 几乎完全相同。而且如果您需要尽一切可能提高性能则使用 SelectNodes 可能更好。下面的伪代码说明了 SelectSingleNode 的当前实现 Function SelectSingleNode(xpathExpr As String) As XmlNode Dim nodes As XmlNodeList SelectNodes(xpathExpr) Return nodes(0)End Function 该方法在内部调用 SelectNodes并且返回第一个匹配节点。但是请注意XmlNodeList 是动态生成的 — 只有在收到请求时才会搜索下一个节点。 一种更好的查询单个节点的方式是向 SelectNodes 传递一个能够返回单个节点的更为精确的 XPath 表达式。其思想是避免使用如下所示的一般性通配符表达式 NorthwindEmployees/Employee 您应当在 XPath 表达式上放置一个更强的筛选器以便它返回大小正确的节点子集。要只获得第一个节点请添加一个额外的谓词以便在找到第一个匹配项之后停止查询 NorthwindEmployees/Employee[position() 1] 这通常是 XPath 最佳做法并且并不特别归因于 .NET Framework 实现。可以对该方法进行提炼和概括以便根据需要调整节点集的大小。下面的查询字符串显示了如何获得头 n 个匹配的节点 NorthwindEmployees/Employee[position() n1] 当您需要对采用某种形式的节点标识的选定节点执行操作时我建议您使用 XmlNode 的 SelectNodes 而不是 XPathNavigator 的实例来执行 XPath 查询。如果您需要将该节点作为 XmlNode 类的实例进行进一步的管理则使用 SelectNodes 可以简化代码。 用 XPathNavigator 编程 让我们再学习一点儿有关 XPathNavigator 的编程接口的知识。通常不管使用哪个应用程序级别的 API对 XML 数据源执行 XPath 查询所需的步骤序列大致是相同的 获得对支持 XPath 的文档类的引用例如XPathDocument 或 XmlDocument 类的实例。 为指定的数据存储区创建一个导航器对象。 如果您计划以后重用 XPath 表达式则还可以对其进行预编译。 调用导航器的 Select 方法以采取操作。 导 航器对象的编程接口定义在 XPathNavigator 抽象类中。尽管您通常使用导航器对象来执行 XPath 查询但让 XPathNavigator 类代表更为通用的组件是不值得的。导航器是一个一般性的接口它充当类似于游标的探测器以探测任何将其内容作为 XML 公开的数据存储区。尽管在功能上类似于 XML 读取器但对于简单的读取操作而言导航器却没有前者快速和有效这是因为它是一个树导航器并且专门用于进行检索。如果您只需要读取 XML 文档请使用 XML 读取器如果您需要执行查询请使用导航器。请记住现在导航器在完全内存映射数据源上工作。 从功能上 说XPathNavigator 类与只是将导航文档内容所需的所有方法组合在一起的伪类没有太大不同。较大的差异在于XPathNavigator 是一个与文档类完全分离的独特组件。换句话说XPathNavigator 代表某种已经映射到 XML 数据模型的数据存储区的 XML 视图。 图 4 枚举了 XPathNavigator 类上的可用属性。像 XML 读取器和 XMLDocument 类一样XPathNavigator 利用了名称表来更有效地存储重复字符串。该属性集看起来像是表征 XmlTextReader 类中当前节点的属性的子集。 值得重复说明的是XPathNavigator 的 Select 方法返回一个迭代器对象该对象的当前元素被作为导航器XPathNavigator 类向后引用。要访问和处理节点信息您只能使用该导航器的属性。图 4 中的属性是只读的并且更为重要的是它们没有映射到 XmlNode 类的实例。如果您需要将该节点作为 XmlNode 对象进行操作例如为了应用更改以确保将 XmlDocument 用作数据存储区类然后将迭代器的当前元素转换为 IHasXmlNode。从引用类型中IHasXmlNode 调用 GetNode 方法该方法返回基础节点的 XmlNode 实例。在其他所有情况下对节点的访问权限是只读的。 导航器对象提供了一组丰富的方法我基于这些方法的功能将它们划分为三个主要的组选择、移动和杂项。以下代码片段选择节点的子孙。用于获得祖先的代码几乎完全相同 Dim doc As XPathDocument New XPathDocument(fileName)Dim nav As XPathNavigator doc.CreateNavigator()nav.SelectDescendants(nodeName, nsUri, selfIncluded) SelectDescendants 采用该节点的本地名称并选择子孙。NsUri 变量指示子孙节点的命名空间 URI如果存在的话。SelfIncluded 布尔型变量是一个标志它指示是否应该将该上下文节点包括在节点集中。 图 5 包含了 XPathNavigator 的移动方法的列表。您可以按照命名空间限制向任一方向跳跃 — 向前或向后从同辈到同辈。您可能已经注意到有三组不同的移动方法它们分别适用于元素、属性和命名空间节点。只有 MoveTo 和 MoveToRoot 方法可以在任何节点不管类型如何上调用。此外属性和命名空间还具有用于返回其值的方法GetAttribute 和 GetNamespace。当被选择时导航器的 Name 属性返回命名空间前缀。Value 属性返回 URI。 图 6 对 XPathNavigator 类上定义的其他所有方法进行了分组。其中几个方法与 XPath 表达式有关。XPath 表达式是一个代表位置路径的字符串尽管它不仅仅是普通的命令字符串。它具有由 XPathExpression 类封装的环绕上下文。表达式的上下文包括返回类型和命名空间信息。XPathExpression 类不是可公开创建的。要获得它的新实例必须取得一个 XPath 字符串表达式并将其编译为 XPathExpression 对象。下面的代码片段显示了如何编译表达式并显示它的预期返回类型 Dim expr As XPathExpression nav.Compile(xpathExpr)Console.WriteLine(expr.ReturnType.ToString())nav.Select(expr) 已编译的 XPath 表达式可以由 Select、Evaluate 和 Matches 方法使用。这里的术语“编译”并不意味着 XPath 表达式成为可执行的表达式。更简单地说来必须将编译操作视为通过收集各种信息片段产生对象的过程。表达式可以返回除节点集以外的各种类型的值。在这种情 况下使用 Evaluate 方法计算该表达式然后将返回的一般对象转换为特定的类型。Select 是一个更为特殊的方法因为它假定返回类型是节点集并且将这些节点插入到迭代器中。 对节点集进行排序 XPathExpression 类中内置的一个有趣的扩展是能够在将节点集传回调用方之前对其进行排序。要添加排序算法需要调用 XPathExpression 对象上的 AddSort 方法。AddSort 具有两种形式 Sub AddSort(expr As Object, comparer As IComparer)Sub AddSort(expr As Object, order As XmlSortOrder, _ caseOrder As XmlCaseOrder, lang As String, _ dataType As XmlDataType) Expr 参数表示排序关键字。它可以是表示节点名称的字符串也可以是另外一个能够计算为节点名称的 XPathExpression 对象。在第一个重载中comparer 参数引用实现了 IComparer 接口的类的一个实例。该接口提供了 Compare 方法该方法实际上用于比较一对值。如果您需要指定一个自定义算法以便对节点进行排序则请使用该重载。 第二个重载总 是根据 dataType 参数的值执行数值或文本比较。此外您还可以指定排序顺序升序或降序甚至指定大写和小写字母的排序顺序或者您可以通过使用值 XmlCaseOrder.None 完全忽略大写。最后lang 参数指定要使用哪种语言进行比较。语言名称还应当指定区域设置。例如要指示美国英语最好使用“us-en”而不是简单地使用“en”。 让 我们更深入地讨论一下 IComparer 接口。为了对对象数组进行排序.NET Framework 提供了几个预定义的比较器类包括 Comparer 和 CaseInsensitiveComparer。比较器类相对于大小写比较对象通常为字符串。CaseInsensitiveComparer 完成相同的工作但忽略大小写。要在代码中使用这两个类请确保导入 System.Collections 命名空间。Comparer 类不具有公共构造函数但是通过 Default 静态属性提供了单个实例。例如 expr.AddSort(lastname, Comparer.Default); 如果需要您还可以创建自己的比较器类。以下代码显示了一个相当平常的 Visual Basic® .NET 实现 Class MyOwnStringComparer Implements IComparer Public Function Compare(x As Object, y As Object) _ As Integer Implements IComparer.Compare Dim strX As String CType(x, String) Dim strY As String CType(y, String) Return String.Compare(strX, strY) End SubEnd Class The Compare method should如果两个字符串相等则 Compare 方法应当返回 0如果 x 先于 y则该方法返回一个大于 0 的值如果 y 先于 x则它返回一个负值。 该类还可以定义在应用程序的体中并且不需要单独的程序集。以下代码将一个自定义比较器与一个 XPath 表达式相关联 Dim comp As MyOwnStringComparer New MyOwnStringComparer()expr.AddSort(lastname, comp) 图 7 显示了该技术的一个应用。在为 XML 文档创建导航器之后示例控制台应用程序编译要使用的表达式。假设的数据源具有以下架构 MyDataSetNorthwindEmployeesEmployee employeeid.../employeeid lastname.../lastname firstname.../firstname title.../title /Employee•••/NorthwindEmployees/MyDataSet 按照单个节点进行排序是容易的 — 只须将节点名传递给 AddSort 方法。按照多个字段进行排序更为复杂。其思想是指示一个由逗号分隔的节点名称列表。但是参数字符串必须是一个能够计算为由逗号分隔的节点名称列表的 XPath 表达式。如果简单地将排序关键字指定为类似于“title, lastname”的形式则您将获得运行库错误因为 XPath 处理程序错误地将其当作实际的节点名称。真正需要的是 XPath 处理程序能够在运行时将其转换为所需头衔和姓氏的表达式如下所示 Dim sortKey As String concat(concat(title, ,), lastname) Concat 关键字标识 XPath 实现提供的预定义 Helper 函数之一。 在图 7 中您还可以了解如何有效地使用迭代器。在使用 XPath迭代器时需要注意的一个要点是代码一次遍历节点集中的所有节点。 您可能需要深入到其中每个节点的子树中。为此请首先克隆导航器以避免放错主要的导航器从而损害最外层的循环 Dim iterator As XPathNodeIterator nav.Select(expr)While iterator.MoveNext()Dim nav2 As XPathNavigator iterator.Current.Clone()nav2.MoveToFirstChild()•••nav2.MoveToNext()•••End While 迭代器上的 Current 属性返回节点集中的当前节点。它计算为 XPathNavigator 类的实例并且可以使用 Clone 方法克隆。 .NET 中的 XSL 概述 XML 转换是用户定义的、试图用另外的等价的语法表达给定文档语义的算法。转换过程包含基于样式表的结构来呈现源文档。样式表是声明性的用户定义文档它包 含用来将一个文档转换为另一个文档的规则集。XSL 是指为了表示 XML 文档的样式表而设计的元语言。XSL 文件最初被想像为 HTML 级联样式表 (CSS) 的 XML 对应物。鉴于此XSL 被设计为可扩展的、用户可定义的工具该工具可以用 HTML 呈现 XML 文档以便进行显示。样式表日益增长的复杂性以及 XML 架构的出现导致了 XSLT 的产生。目前XSL 只是许多派生技术的一个总括性的术语所有这些技术能够更好地形容和实现将 XML 文档样式化的的原始思想。XSL 所包含的各种组件是在代码中使用的实际软件实体XSLT、XPath 和 XSL 格式化对象 (XSLFO)。 XSLT 程序是一个一般性的转换规则集其输出可以是任何基于文本的语言包括 HTML、RTF 等等。正如前文提到的那样XPath 是一种查询语言XSLT 程序可以利用它来选择源 XML 文档的特定部分。XPath 表达式的结果随后由 XSLT 处理程序进行分析和阐述。通常XSLT 处理程序对源文档进行顺序处理但是如果要求访问特定的节点组则它会将该源文档传递给 XPath。 在 .NET Framework 中XSLT 的核心类是 XslTransform。该类位于 System.Xml.Xsl 命名空间中并实现了 XSLT 处理程序。可以采取两个步骤来使用该类首先在处理程序中加载样式表然后根据需要向任意多的源文档应用转换。XslTransform 类只支持 XSLT 1.0 规范。图 8 中的 C# 代码实现了一个命令行 XSLT 转换器。它采用三个命令行参数XML 源、XSLT 样式表和输出文件来设置处理程序并且将转换结果保存到输出文件中。 XslTransform 类 XslTransform 类提供了两个特定于其活动的方法 — Load 和 Transform。该类只有在转换操作期间才能保证以线程安全的方式进行操作。换句话说尽管该类的实例可以由多个线程共享但只有 Transform 方法才可以从多个线程中安全地调用。Load 方法不是线程安全的。Transform 方法读取共享状态并且可以从多个线程中并发运行。图 9 显示了该类的内部体系结构的一部分。在加载样式表之后XSLT 处理程序需要修改它的状态以反映所加载的文档。该操作不会在由锁定语句创建的虚拟边界中以原子方式发生。因此并发运行的线程理论上可以访问同一个 XSLT 处理程序实例从而破坏数据一致性。加载操作是线程敏感的因为它改变了对象的全局状态。 图 9 XSL Transform 类 在 .NET Framework 的版本 1.0 中XslTransform 类附加了链接请求权限集。链接请求指定直接调用方运行代码必须具有的权限。调用方权限在即时编译期间进行检查 [PermissionSet(SecurityAction.LinkDemand, NameFullTrust)]public sealed class XslTransform{ ••• } XslTransform 类的权限集属性由名称表示并且指向内置的权限集之一 — FullTrust。这对用户来说意味着什么呢只有对所有本地资源都具有完全受信任访问权限的调用方该检查涉及直接调用方而不是调用方的调用方才 可以安全地调用到 XSLT 处理程序中。例如如果您通过网络共享调用 XSL 处理程序则会引发安全异常。在 .NET Framework 的版本 1.1 中该权限集已经被移除。 在 .NET Framework XSLT 处理程序的总体行为中可以明确地标识三个阶段样式表文档的加载、内部状态的设置和转换。头两个阶段发生在 Load 方法的上下文中。当然在前面的 Load 调用成功终止之前无法调用 Transform 方法。Load 方法总是同步工作以便当它返回时您可以确保加载步骤已经实际完成。您将不会收到任何指示操作失败或成功的返回值。但是每当 Load 方法发生什么错误时都会引发一些异常。特别地如果您指向一个丢失的样式表则将得到 FileNotFoundException 类型的异常如果 XSLT 脚本包含某些错误则将得到 XsltCompileException 类型的更一般的异常。XsltCompileException 异常提供了样式表中发生错误的行位置和编号。 可以从四个不同的源加载输入样式表URL、XML 读取器、XPathDocument 和 XPathNavigator。不管是哪个源Load 方法的第一个操作都是将该源表示为一个 XPathNavigator 对象。样式表必须进行编译并且考虑到编译器的体系结构导航器是非常有效的对象。“编译”是这样一个过程它简单地从原始样式表中提取一些信息并将 其存储在方便的数据结构中以便进一步使用。这些数据结构的整个集合称为 XSLT 处理程序的状态。图 10 显示了 Load 方法的流程。 图 10 Load 方法流程 样式表编译器用从源中读取的数据填充三个内部数据结构。作为已编译样式表对象引用的对象表示样式表内容的一种索引。其他两个对象是表和操作前者包含要执行的 XPath 查询的编译版本后者是各种模板所需的操作。 Transform 方法至少采用两个显式参数 — 源 XML 文档和输出流再加上几个隐式参数。当然已编译的样式表对象是隐式输入参数之一。第二个隐式参数是 XslTransform 的 XmlResolver 属性该属性专门用于解析外部资源的内容。Transform 方法还可以采用第三个显式参数 — 类 XsltArgumentList 的对象。该参数包含被用作转换过程的输入的命名空间限定参数。 XML 源文档被标准化为 XPathNavigator并且向下传递给 XSLT 处理程序。有趣的是Transform 方法具有两种类型的重载。其中一些重载作为 void 方法工作并且只是写入指定的流。其他重载作为函数工作并且明确返回一个 XML 读取器对象。正如我稍后将讨论的那样该功能提供了一个非常有趣的机会实现异步 XSLT 转换。在图 11 中可以看到 Transform 方法的执行流。 图 11 Transform 方法 Transform 方法还使您可以使用 XsltArgumentList 类的实例向样式表传递参数。在以这种方式向 XSLT 脚本传递参数时您无法指定哪个模板调用将实际使用这些参数。您只是以全局方式将参数传递给 XSLT 处理程序。负责处理模板的内部模块随后将根据需要读取和导入这些参数 XsltArgumentList args new XsltArgumentList();args.AddParam(MaxNumOfRows, , 7); AddParam 方法在参数列表中创建了一个新项。该方法需要三个参数参数名称、命名空间 URI如果该名称由命名空间前缀限定以及一个代表实际值的对象。不管您用来将参数值包装到参数列表中的 CLR 类型如何该参数值都必须对应于有效的 XPath 类型字符串、布尔型、数字、节点片段和节点集。数字对应于双精度类型而节点片段和节点集等价于 XPathNavigators 和 XPath 节点迭代器。 参数和扩展对象 XsltArgumentList 不是基于集合的类。它不是派生自集合类也没有实现任何典型的列表接口如 IList 或 ICollection。XsltArgumentList 类是围绕几个哈希表生成的 — 一个用于存放 XSLT 参数一个用于收集扩展对象。扩展对象是 .NET 对象的一个活动实例它可以作为参数传递给样式表。例如可以用各种方式扩展 XSLT 脚本以获得嵌入式 XPath 库未提供的功能。XslTransform 类支持 xsl:eval 指令该指令使您可以将 VBScript 插入到样式表中。将自定义代码嵌入到脚本中的替代方法是使用 msxsl:script 元素。该新指令支持托管语言并且提供对整个 .NET Framework 的访问 msxsl:script language language implements-prefix prefix •••/msxsl:script 受支持的语言包括 C#、Visual Basic 和 JScript®。Language 属性不是强制性的并且如果未指定该属性则默认为 JScript。但是Implements-prefix 属性是强制性的。它声明一个命名空间并且将用户定义的代码与它相关联。该命名空间必须在样式表中某处进行定义。此外要使用 msxsl:script 指令该样式表必须包含以下命名空间 xmlns:msxslurn:schemas-microsoft-com:xslt 要定义简单脚本需要在该样式表的根中声明额外的命名空间。例如 xsl:stylesheet version1.0 xmlns:xslhttp://www.w3.org/1999/XSL/Transform xmlns:msxslurn:schemas-microsoft-com:xslt xmlns:dinourn:dino-scripts 该声明是调用 msxsl:script 指令所需要的。该命名空间只是将某些由用户定义的脚本组合在一起。现在需要使用前缀“dino”来限定对 msxsl:script 块中定义的任何函数的任何调用。在样式表的体中调用 msxsl:script 块中定义的任何函数 xsl:template matchlastname TD styleborder:1px solid black xsl:value-of selectdino:PrepareName(., ../firstname) / /TD/xsl:template 如果您在参数的前后加上引号则它们将被视为文字值。要确保托管函数收到节点值请使用与用于 xsl:value of 指令的 select 属性的表达式相同的表达式。 msxsl:script 指令并不总是最佳的解决方案。它只支持作为 XSLT 处理程序的一部分导入的一组有限的命名空间。例如您无法使用 System.Data 命名空间。脚本适合于一次性的操作例如分析字符串或检索当前时间。至于更为强大的替代解决方案请考虑扩展对象。 扩展对象只是一个具 有一些公共方法的托管类。唯一的要求是可调用的方法接受 XPath 类型的参数或可以强制转换到该类型的参数。与嵌入式脚本它们被自然地定义在样式表的体中不同扩展对象是必须以某种方式插入到样式表中的外部资源。扩 展对象参数必须按照以下代码所示进行传递 ExtensionObject o new ExtensionObject();// *** set properties on the object if neededXsltArgumentList args new XsltArgumentList();args.AddExtensionObject(urn:dino-objects, o);XslTransform xslt new XslTransform();xslt.Transform(doc, args, writer); 在 XSLT 脚本中可以像使用嵌入式脚本那样引用扩展对象上的方法。在下面的代码片段中DoSomething 是与带有“dino”前缀的命名空间相关联的扩展对象上的方法 xsl:template matchlastname TD styleborder:1px solid black xsl:value-of selectdino:DoSomething(., ../firstname) / /TD/xsl:template 扩展对象的方法被作为静态方法调用进行处理这意味着如果您具有多个带有相同方法名称的对象则最好使用不同的命名空间。 使用扩展对象比使用嵌入式脚本更为可取这至少有两个原因。首先扩展对象提供了好得多的代码封装更不用提实现类重用的可能性以及可以使用任何托管类型这一事实。其次最后可以得到能够从更加无缝的代码维护中受益的更紧凑的分层样式表。 异步 XSLT Transform 方法具有几个能够返回 XML 读取器的重载 XmlReader Transform(XPathNavigator input, XsltArgumentList args);XmlReader Transform(IXPathNavigable input, XsltArgumentList args); 这些重载的签名和行为与其他重载稍有不同。首先输入文档必须是 XPathNavigator 或 XPathDocument。更重要的是这些方法不接受任何代表输出流的参数。实际上转换过程的输出不是写出到流中而是在流中创建并且通过 XML 读取器返回给用户。 .NET Framework 中的整个 XSLT 过程通过创建一个中间数据结构输入导航器工作在该数据结构中样式表的内容被用作底层的基础。在该样式表源中发现的任何 xsl 标记都被替换为展开的文本或产生自嵌入式模板的任何调用序列。最终输出看起来像是已编译的程序其中直接语句与子例程调用交替出现。这些语句被称为输出记 录而模板则充当子例程的角色。当 Transform 方法获得可以写入的输出流时XSLT 处理程序遍历所有记录并将文本刷新到流中。如果已经请求 XML 读取器则处理程序会创建某个内部读取器类的实例并将其返回给调用方。在调用方显式请求读取缓存的输出记录之前不会执行任何转换参见图 12。 图 12 XSL 转换过程 当 Transform 方法返回时读取器处于其初始状态这意味着它尚未针对读取操作进行初始化。每当您从读取器中弹出一个元素时都将正确地展开并返回一个新的输出记录。这 样您可以完全控制转换过程并且可以实现许多奇特的功能。例如您可以向用户提供反馈基于运行库条件和用户角色丢弃节点或者使该过程在辅助线程上异 步发生。有关异步转换的示例请参见本文的代码下载。 asp:xml 标记 在结束本文之前我希望考察 一个由 asp:xml 标记标识的特殊 ASP.NET 服务器控件。该控件是 XslTransform 类的声明性对应物。可以使用 XML 服务器控件在 Web 页中嵌入 XML 文档。在需要可供客户端使用的 XML 数据岛时使用该控件很方便。数据岛是 HTML 页中引用或包含的 XML 数据。XML 数据可以用内联方式包含在 HTML 中也可以存储在外部文件中。通过将该控件的能力与执行特定于浏览器的转换的样式表相结合可以将服务器端 XML 数据转换为不受浏览器影响的 HTML。例如以下代码嵌入指定的 XML 文件的内容就像由该页中的样式表进行转换一样 div asp:xml runatserver idxmldata documentsourcedata.xml transformsourceie5.xsl //div XML 服务器控件可以通过编程方式进行配置并且通过字符串DocumentContent 属性以及通过 XmlDocument 对象Document 属性接受源 XML。转换元素可以通过指向 XSL 文件的 URL 或者通过 XslTransform 类的实例Transform 属性提供。如果需要还可以使用 TransformArgumentList 属性指示参数。该组件与 HttpBrowserCapabilities 类一起为常见需要数据驱动 Web 页和特定于浏览器的输出提供了一种了不起的解决方案。 请注意只有格式规范的 XML 数据才能与 asp:xml 控件一起使用。更简单地如果需要刷新任何文件的内容则可以使用 Response.WriteFile 方法。 小结 在 本文中我将 XPath 作为在托管应用程序中执行 XML 查询的语言加以分析并且讨论了其实现的几个方面。在 .NET Framework 中XPath 运行库为其他令人困惑的部分其中第一个是 XSLT提供了公用基础结构。我还分析了 XSLT 处理程序的关键方面并且提供了它的几个有趣的应用例如异步处理和 ASP.NET 控件。 有关背景信息请参阅 Applied XML Programming for Microsoft .NET by Dino Esposito (Microsoft Press, 2002)Essential XML Quick Reference: A Programmers Reference to XML, XPath, XSLT, XML Schema, SOAP, and More by Aaron Skonnard and Martin Gudgin (Addison-Wesley, 2001)XPathNavigator over Different Stores MSDN Web Services Developer Center 转载于:https://www.cnblogs.com/chenying99/archive/2011/03/10/1980209.html