利用 DataSetNavigator 在数据集上进行 XPath 查询(转载---来自MSDN)
2004-09-22 11:49
671 查看
利用 DataSetNavigator 在数据集上进行 XPath 查询
发布日期: 9/21/2004 | 更新日期: 9/21/2004Arpan Desai
Microsoft Corporation
2004 年 8 月
适用于:
XML
DataSetNavigator
摘要:Arpan Desai 讨论了 DataSetNavigator,它提供 XML 编程模型的强大功能和灵活性,同时避免了将整个 DataSet 转换成 XmlDataDocument 对象的开销。
单击此处可下载本文的代码示例。
本页内容
简介 | |
在数据集上构建 XPath Navigator | |
DataSetNavigator 实现的详细信息 | |
用法 | |
小结 |
简介
一段时间以来,Dare 一直要求我为 MSDN 写一篇文章。既然 Microsoft Visual Studio 2005 Beta 1 已经(最终)发布了,我就抽出时间来写一下我这段时间以来的一些想法:DataSet 上的 XPathNavigator。XmlDataDocument 最初作为一个组件出现,它允许用户具有一个 Microsoft ADO.NET DataSet 数据的可编辑的层次视图。主要用例是在 DataSet 上执行 XSLT 转换的功能,以便生成用于在网页上表示的 HTML。遗憾的是,在 XSLT 处理过程中 XmlDataDocument 的性能通常都是一个瓶颈。
这个问题的一个解决方案就是利用 DataSet 上的 WriteXml() 方法并将序列化的内容加载到 XmlDocument 或 XPathDocument 类中。尽管使用这种方法会显著地提高性能,但是由于需要序列化和重新解析 XML 数据,所以它仍然不是最优的。此外,要进行转换或查询的数据现在同时驻留在 DataSet 和 XmlDocument/XpathDocument 中,这意味着极大的增加内存使用。理想的解决方案应该具有本机 XML 存储区(例如 XPathDocument)的性能,同时占用最小的内存开销。
本文说明一个名为 DataSetNavigator 的类的实现,它尝试以理想的方式来解决这个问题。
返回页首
在数据集上构建 XPath Navigator
XPathNavigator 是 XML 数据源上的只读光标。XML 光标就像每次聚焦于一个 XML 节点上的镜头,但是与基于推的 API(如 XmlReader)不同,该光标可以在任意给定时间内置于 XML 文档的任意位置。XPathNavigator 是用于在非 XML 数据上实现 XML 接口的优秀备选,因为它允许以实时方式构建数据源的 XML 视图,而不必将整个数据源转换成 XML 树。通过适当的实现,您可以使用它来查询文件系统、Windows 注册表、Active Directory 存储区或任意其他类型的分层数据存储区。在以前的文章中,Steve Saxon 曾经使用 ObjectXPathNavigator 在对象图表上创建过一个 XPathNavigator。
Microsoft .NET Framework 中的 XslTransform 类利用 XPathNavigator 在这些源上执行 XSLT 处理。此外,XPathNavigator API 还启用了 XPath 查询。通过实现 DataSetNavigator,我们可以在 DataSet 内容上同时执行 XSLT 转换和 XPath 查询。
一个必须要提出的问题是:为什么 DataSetNavigator 的实现会比 XmlDataDocument 速度快呢?XmlDataDocument 具有性能问题的一个根本原因在于它具有可编辑的能力。无论何时在 XmlDataDocument 的实例中发生更改,该更改就会传播到与它相关联的 DataSet。相反,对 DataSet 所做的任何更改也会同步附属的 XmlDataDocument。即使没有进行更改,这样设计的开销也会防止在查询或转换过程中的最优性能。在这两个方案中,不需要进行编辑;因此我们可以通过忽略同步功能的开销,从而创建更有效的 XPathNavigator 实现。
返回页首
DataSetNavigator 实现的详细信息
目标相当简单:在 DataSet 顶端完成快速、轻量级的 XPathNavigator 实现。要实现的最复杂的功能就是理解 DataSet 中的嵌套关系,这样就可以借助于 DataSetNavigator 来表示层次结构。实现 DataSetNavigator 的第一步就是理解如何使用 XPathNavigator 对基础数据源进行模型化。当不为 DataSet 提供 XML 架构时,由 XmlDataDocument 和 WriteXml() 方法用于生成 XML 的规则就相当简单了。
• | DataSet 的名称为 XML 中的根元素。 |
• | 不是嵌套关系中子元素的任意表中的行,均为根元素的子元素。 |
• | 表的列均为每行元素中的子元素。 |
• | 如果存在任意嵌套子行,这些行也均为该行元素的子元素。 |
树是从一系列节点中构建的,所有这些节点都派生自 DataSetNode 类。抽象 DataSetNode 类具有要求遍历所生成树的基本导航,而且具有几个非常重要的成员:
• | parent - 父成员指向当前节点的父级 DataSetNode。 |
• | children - 子成员是 DataSetNodes 的数组,该 DataSetNodes 表示当前节点的子节点。 |
• | siblingPosition - siblingPosition 成员表示相对于其同级的当前节点位置的基于零的索引。这是必需的,因此在同级间的移动可以更简单有效的实现。 |
• | localName - localName 成员指向原子化的字符串,它是当前节点的本地名称。XPathNavigators 利用 XmlNameTable 对本地名称、命名空间前缀以及给定文档内的命名空间 URL 进行原子化和公开处理。这考虑到了在搜索这些项目时发生的低开销对象引用比较,而不是高开销的字符串相等比较。 |
• | TopNode - 这是由位于 DataSet 上的 XPathNavigator 公开的顶级元素节点。 |
• | TableRowNode - 这种元素节点位于 DataSet 内的独立行上。 |
• | ColumnRowNode - 这种元素节点位于特定列、特定行上。 |
• | RootNode - 每个文档都具有根;这种节点是极其简单的节点类型,它表示文档的根。 |
• | CellValueNode - 我们需要一种表示驻留在 DataSet 中实际数据的方式。树中的每个 ColumnRowNode 都具有包含该数据的单一 CellValueNode 子节点。请注意,CellValueNode 的实现并不会导致对已经位于 DataSet 中的数据进行复制,而是返回了 DataSet 实例。 |
返回页首
用法
DataSetNavigator 的用法类似于任何其他 XPathNavigator。DataSetNavigator 可以被传递到 XslTransform 类,以便进行 XSLT 处理,如下面的示例所示:DataSet myDataSet = new DataSet(); ... DataSetNavigator myNavigator = new DataSetNavigator(myDataSet); XslTransform myTransform = new XslTransform(); myTransform.Load("transform.xsl"); myTransform.Transform(myNavigator, null, Console.Out);
此外,可以针对 DataSet 执行 XPath 查询,如下面的示例所示:
using System; using System.Data; using System.Xml; using System.Xml.XPath; using Microsoft.Xml; public class DataSetNavTest{ public static DataSet CreateDataSet(){ DataSet custDS = new DataSet("Books"); DataTable ordersTable = custDS.Tables.Add("Book"); DataColumn pkCol = ordersTable.Columns.Add("BookID", typeof(Int32)); ordersTable.Columns.Add("Title", typeof(string)); ordersTable.Columns.Add("Quantity", typeof(int)); ordersTable.Columns.Add("UnitPrice", typeof(decimal)); ordersTable.Columns.Add("Category", typeof(string)); ordersTable.PrimaryKey = new DataColumn[] {pkCol}; ordersTable.Rows.Add(new Object[]{101, "Quantum Physics for Beginners", 2, 50, "Science"}); ordersTable.Rows.Add(new Object[]{201, "Repair your car with twine", 100, 24.99, "Automotive"}); ordersTable.Rows.Add(new Object[]{301, "The Secret of Life, The Universe and Everything", 42, 41.99, "Humor"}); custDS.AcceptChanges(); return custDS; } public static void Main(string[] args){ DataSet ds = CreateDataSet(); Console.WriteLine(ds.GetXml()); DataSetNavigator nav = new DataSetNavigator(ds); XPathNodeIterator iter = nav.Select( "/Books/Book[(UnitPrice * Quantity) > 1000]" ); while( iter.MoveNext() ){ /* print title and total price of order using XPath queries*/ string itemTotal = iter.Current.Evaluate( "UnitPrice * Quantity").ToString(); string itemTitle = iter.Current.Evaluate("string(Title)").ToString(); Console.WriteLine("+{0} = {1}", itemTitle, itemTotal ); /* print title and total price of order using DataSet APIs */ DataSetNavigator nav2 = (DataSetNavigator) iter.Current.Clone(); DataRow row = nav2.GetDataRow(); string itemTotal2 = (((decimal)row["UnitPrice"]) * ((int)row["Quantity"])).ToString(); string itemTitle2 = row["Title"].ToString(); Console.WriteLine("-{0} = {1}", itemTitle2, itemTotal2 ); } } }
DataSetNavigator 除了作为 XPathNavigator 外,还实现了 IDataSetPosition 接口。这种接口旨在返回当前 DataSetNavigator 所定位的 DataSet 中的位置,它考虑到需要访问 DataSet 的实际 DataRows/DataColumns 的高级方案。IDataSetPosition 公开了 GetPositionType() 方法,该方法返回当前状态的一个枚举值:
• | DataSetPosition.DataSet - DataSetNavigator 位于 DataSet 上。调用 GetDataSet() 将会成功地返回当前 DataSet。调用 GetDataRow() 或 GetDataColumnIndex() 将会失败,因为该 Navigator 没有位于特定行或列上。 |
• | DataSetPosition.Row - DataSetNavigator 当前位于特定的 DataRow 上。调用 GetDataSet() 将返回当前 DataRow 作为其组成部分的 DataSet。调用 GetDataRow() 将返回当前的 DataRow。调用 GetDataColumnIndex() 将产生一个错误。 |
• | DataSetPosition.Cell - 这表示 DataSetNavigator 位于特定单元格上。单元格被视为单个 DataRow 和单个 DataColumn 的交集。调用 GetDataSet()、GetDataRow() 或 GetDataColumnIndex() 将会在此例中全部成功。 |
返回页首
小结
在初步测试中,根据要进行转换的数据大小和样式表的复杂程度,DataSetNavigator 在任何位置都比在 XmlDataDocument 上运行相同的转换的速度要快 2-50 倍。由于不再发生重新解析 DataSet 的内容这一事实,DataSetNavigator 也比当前可用的 XmlDocument 或 XPathDocument 解决方案快 2-5 倍。当前的 DataSetNavigator 相当地简单,并且没有集成任何有趣的功能。缺失的一项功能就是对命名空间的支持。当前的方法就是将 DataSet 转化成 XML 支持命名空间,以便在它们与各个 DataSet 部分相关联时进行序列化。当前的 DataSetNavigator 并没有提供这些命名空间。添加该功能将会相当简单,我将它作为感兴趣读者的一个练习。
转到原英文页面
相关文章推荐
- vs2005中利用自动生成数据集、ObjectDataSource、Gridview进行组合查询
- 利用DataSet数据集进行数据库更新及数据表复制
- 在dataset中使用xpath查询,进行distinct结果集
- 利用游标对查询的数据集进行遍历
- SQL Server使用Merge语句当源表数据集为空时,无法进行查询的问题
- 练习题——Gson解析、利用JDBC连接数据库进行数据的存取及查询等的综合
- android中利用webservice进行天气预报查询
- mysql利用CONCAT进行关键字查询,多字段匹配
- [翻译]利用Lucene.Net进行文档递归查询
- 利用多核多线程进行程序优化-转载
- 利用TCP协议进行ping(转载自shaunfang)
- 【Mysql】利用group by附带having进行聚类查询
- spring data jpa 利用@Query进行查询
- 浅谈C#中的多态及相关知识(主要内容来自msdn) -转载(benzite)
- android利用ksoap2返回复杂数据,数据集(dataset)
- PHP,Mysql-根据一个给定经纬度的点,进行附近地点查询–合理利用算法
- 如何利用客户端缓存对网站进行优化[转载]
- 利用有监督的离散算法对数据集的属性进行离散,并保存离散后的数据集
- 使用Xpath对XML进行模糊查询
- Java,Mysql-根据一个给定经纬度的点,进行附近500米地点查询–合理利用算法