2

我有一个文件,它本质上是一个 XPath 列表,如下所示:

/Options/File[1]/Settings[1]/Type[1]
/Options/File[1]/Settings[1]/Path[1]
/Options/File[1]/Settings[2]/Type[1]
/Options/File[1]/Settings[2]/Path[1]
/Options/File[2]/Settings[1]/Type[1]
/Options/File[2]/Settings[1]/Path[1]

我需要在中等大小的 XML 文件(~3-5MB)中从这些 XPath 指向的元素中获取值。使用 XPathSelectElement 效果很好,但速度极慢。有没有更快的方法来使用 Linq to XML 甚至手动遍历 XML?

在一个相关问题中,XPath 中的索引值和从 XElement 返回的元素顺序是否保证相同?例如,这些返回是否相同:

xdoc.XPathSelectElement("/Options/File[1]/Settings[2]);

xdoc.root.Elements("File").ElementAt(0).Elements("Settings").ElementAt(1);
4

3 回答 3

2

索引 XPath(第 n 个孩子)通常很慢,因为需要遍历所有孩子直到您需要的那个。要检查 - 对于相对较大的文件,请尝试选择第一个孩子和最后一个孩子并比较差异(每个重复约 1000 次并使用秒表测量)。

如果您的 XPath 都像您所展示的那样,您可以通过在迭代时缓存子节点来手动进行选择。

XML 中元素的顺序很重要,因此普通的 XML API 将始终保持元素的顺序。请注意,属性的顺序对于 XML 并不重要,因此属性的顺序在查询(不太可能,但理论上可能)和不同的 API 之间可能不同。

于 2012-04-03T21:53:09.567 回答
2

我刚刚遇到了与您类似的问题:使用一堆索引 XPath 表达式在中等大小的 xml 文件(3 MB)中选择一些节点时,我的表现很糟糕。

但与您的解决方案相反,我在 XPath 表达式的每个部分都没有索引。因此,我尝试使用 XPath() 放弃 LINQ to XML XElement.XPathSelectElement,而是XPathNavigator通过创建XPathDocument并调用CreateNavigator(). 在我使用的导航器上SelectSingleNode

使用XElement.XPathSelectElement它我花了 137.3 秒来完成所有选择(顺便说一下,程序的其余部分只用了大约 3 秒)。

现在使用XPathNavigator.SelectSingleNode选择总共需要 1.2 秒……这几乎是 115 倍

因此,如果有人需要更快的 XPath 查询并且不想自己解析查询:如果可能的话,不要使用 LINQ to XML,它的实现似乎非常糟糕。

于 2012-09-14T09:39:52.047 回答
1

我想这就是我要去做的。我确信可能会有更多的性能改进,例如 Alexei 的建议,但在我有限的测试中,这已经至少快了 10 倍。

    private XElement GetElementFromXPath(XDocument xDoc, string xPath)
    {
        string[] nodes = xPath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
        XContainer xe = xDoc.Root;
        for (int i = 1; i < nodes.Length; i++)
        {
            string[] chunks = nodes[i].Split(new char[] { '[', ']' });

            int index = 0;
            if (Int32.TryParse(chunks[1], out index))
                xe = xe.Elements(chunks[0]).ElementAt(index - 1);
        }
        return (XElement)xe;
    }

这假定除根以外的所有元素都在 XPath 中与它们的索引号一起列出(这对我的场景来说是正确的)。

于 2012-04-04T16:43:38.850 回答