【问题标题】:How to implement a simple XPath lookup如何实现简单的 XPath 查找
【发布时间】:2009-07-23 03:13:37
【问题描述】:

我们有一个 XML 文件,其中有一个非常简单的 XLink 实现:

<root xmlns:xlink="http://www.w3.org/1999/xlink">
  <firstChild id="ID1" />
  ...
  <ref xlink:href="#ID1" />
</root>

让我们假设 XLink 实现不会比这更复杂。然而,重要的一点是引用的元素(在本例中为 firstChild)可以出现在文档中的任何位置,层次结构中的任何位置。

在 XPath 查找中,您可以使用如下表达式找到 节点引用的元素:

//*[@id='ID1']

使用LINQ to XML 的最佳等价物是什么?我会按照以下思路考虑:

XDocument doc = XDocument.Load("file.xml");
var dest = xDoc.Descendants().Where(e => (string)e.Attribute("id") == "ID1").SingleOrDefault();

我还没有实际测试过。但一般来说,如果 XML 文档很大,那么 LINQ 方式是否会效率低下(因为它使用 XDocument 上所有后代的枚举)?恢复到 XPathNavigator 并只使用 XPath 表达式会更好吗?

如果这种事情在LINQ中可以做,有没有比我写的更好的方法? LINQ 对我来说仍然只有几天的历史......它很棒,但我想知道它是否对某些操作有效率限制。

【问题讨论】:

    标签: .net xml linq xpath linq-to-xml


    【解决方案1】:

    XPathNavigator 在这里不会更有效率,因为它仍然必须枚举所有后代才能找到它们——那里没有魔法尘埃。如果您希望它比这更有效,您将需要一个索引,并且没有内置的 XML API 开箱即用地提供它们,因此您必须推出自己的索引。例如:

    XDocument doc = ...;
    var id2elem = (from e in doc.Descendants()
                   let id = e.Attribute("id")
                   where id != null
                   select new { Id = id.Value, Element = e })
                  .ToDictionary(kv => kv.Id, kv => kv.Element);
    

    然后在需要时使用该字典按 ID 查找节点。显然,仅当查找相对频繁时才值得这样做,而不是只需要执行一次或两次。

    【讨论】:

    • 正是我想要的:)
    【解决方案2】:

    如果我是你,我也会这样做。除了 where 子句:

    from e in xDoc.Descendants()
    let id = e.Attribute("id") ? e.Attribute("id").Value : null
    where (id == "ID")
    select e
    

    所以不需要进行类型转换。

    关于你的第一个问题,据我所知,微软停止了 XPath 实现的开发,所以我相信,即使目前还没有,LINQ to XML 与 XPath 相比会有更好的优化。

    【讨论】:

    • 如果文档中的某个节点没有@id,这将抛出NullReferenceException
    • 此外,在 XPath(在 XPathNavigator 中实现)或 LINQ 中都没有“优化”!这不是魔术。它完全按照您的预期工作,即无处不在的线性扫描。它不能使用索引,因为它怎么知道你要查找什么,以及要索引什么?如果有的话,对于某些类型的查询,XPathNavigator 实际上可能更快,因为它的节点是双链接的,而 XLINQ 的节点是单链接的(所以在 XPathDocument 中获取前面的兄弟是 O(1),但在 XLINQ 中是 O(N)) .
    • 优化是指 MS 如何实现代码的方式。就像每个浏览器实现 JS 引擎的方式一样,目前 Safari、Chrome 速度最高,IE 次之。他们都使用相同的 JS 代码进行了测试,唯一的区别是浏览器的执行策略和算法如何。我说的优化是一样的,MS会努力让LINQ跑得快(呃)。
    • 您认为如何让它运行得更快?请记住,仍然没有魔法。任何速度的提高都必须来自更好的数据结构和/或算法。你知道有什么更好的可以加快速度?实际上,XLINQ 的唯一好处是您可以将它与 Parallel LINQ 一起使用。
    • 顺便说一句,您编辑的代码比他的代码长,而且实际上并没有买任何东西。你说你想避免类型转换,但为什么呢?它使用XAttribute 重载转换运算符到字符串,这将与您的代码完全相同,但更短。
    【解决方案3】:
    from e in doc.Descendants()
    where (string)e.Attribute("id") != null
    select e;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-19
      • 1970-01-01
      • 2011-07-19
      • 1970-01-01
      相关资源
      最近更新 更多