我有一个基本上是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);
答案 0 :(得分:2)
索引XPath(第n个孩子)通常很慢,因为需要遍历所有孩子,直到你需要的孩子。要检查 - 相对较大的文件尝试选择第一个孩子和最后一个孩子并比较差异(每个重复约1000次,并使用StopWatch进行测量)。
如果您已经显示XPath,则可以通过在迭代时缓存子节点来手动进行选择。
XML中的元素顺序很重要,因此普通的XML API将始终保持元素的顺序。请注意,属性的顺序对于XML来说并不重要,因此不同API之间的属性顺序可能不同(不太可能,但理论上可行)。
答案 1 :(得分:2)
我遇到了类似的问题:我使用一堆索引的XPath表达式在中等大小的xml文件(3 MB)中选择一些节点时表现糟糕。
但与您的解决方案相反,我在XPath表达式的每个部分都没有索引。所以我尝试使用XPath(XElement.XPathSelectElement
)抛弃LINQ to XML,而是通过创建XPathNavigator
并调用XPathDocument
来使用CreateNavigator()
。在导航器上我使用了SelectSingleNode
使用XElement.XPathSelectElement
我花了137.3秒来完成所有选择(顺便说一下,程序的其余部分只使用了大约3秒)。
使用XPathNavigator.SelectSingleNode
选择现在需要1.2秒整数...这是一个差不多115的因素
因此,如果任何人需要更快的XPath查询并且不想自己解析查询:如果可能的话,不要使用LINQ to XML,它似乎在性能方面表现得非常糟糕。
答案 2 :(得分:1)
我认为这就是我要去的地方。我确信可以有更多的性能改进,例如阿列克谢的建议,但在我的有限测试中,这已经至少快了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中的索引号一起列出(对于我的场景也是如此)。