【问题标题】:Which is the best for performance wise: XPathNavigator with XPath vs Linq to Xml with query?在性能方面哪个是最好的:带有 XPath 的 XPathNavigator 与带有查询的 Linq to Xml?
【发布时间】:2012-01-21 18:12:09
【问题描述】:

我有一个应用程序,我在其中使用 XPathNavigator 来迭代节点。它工作正常。

但我想知道,如果我使用 LINQ to Xml....

  1. 我将获得哪些好处(性能、可维护性)?

  2. 使用 XPath、LINQ to Xml 对性能有何影响?

我使用的是 C#.net,VS 2010,我的 .xml 大小适中。

【问题讨论】:

  • 你考虑过测量吗?
  • @MitchWheat 不,我需要将我的代码从 XPathNavigator 更改为 LINQ 到 xml。所以在这样做之前我想知道它
  • 在比较性能时,总是so 特定于场景,要获得准确 的答案,只需要做一件事...试试它和每个方向的时间。
  • @Syed 如果您需要从 XPath 更改为 L2Xml,那么性能问题不是无关紧要吗?如果你无论如何不得不改变,你不妨现在衡量它,做出你的改变,然后再衡量它。假设您已获得更改指令,那么任何性能损失或提升都会变得显而易见。

标签: c# .net-4.0 linq-to-xml xmldocument xpathnavigator


【解决方案1】:

嗯,XPathNavigator 通常会比 Linq to XML 查询更快。但总有“但是”。

Linq to XML 肯定会让您的代码更具可读性和可维护性。阅读 linq 查询然后分析 XPath 更容易(至少对我而言)。此外 - 您将在编写查询时获得智能感知,这将有助于使您的代码正确。 Linq to XML 还可以让您轻松修改数据,如果这是您需要的话。 XPathNavigator 为您提供只读访问权限。

另一方面,如果您真的需要顶级性能,XPathNavigator 可能是您的最佳选择。这仅取决于您当前的情况以及您要完成的工作。如果性能不是问题(XML 文件相当小,您不会对该文件发出很多请求等等),您可以轻松地使用Linq to XML。否则坚持接近XPathNavigator

【讨论】:

    【解决方案2】:

    只是补充一下这里已经说明的内容,整体性能似乎取决于您对相关文档的实际操作。这是我基于一个简单的实验运行得出的结论,该运行比较了 XElement 和 XPathNavigator 之间的解析性能。

    如果是选择节点,遍历这些节点并读取一些属性值:

    • XElement.Element 比 XElement.CreateNavigator.Select 快一个 近似系数 1.5。
    • XElement.CreateNavigator.Select 更快 比 XPathNavigator.Select 大 0.5 倍。
    • XPathNavigator.Select 比 XElement.XPathSelectElement 快 0.5 的近似系数。

    另一方面,如果您还读取每个节点的子节点的值,它会变得有点有趣:

    • XElement.Element 比 XElement.XPathSelectElements 快大约 0.5 倍。
    • XElement.XPathSelectElement 比 XPathNavigator.Select 快大约 3 倍。
    • XPathNavigator.Select 比 XElement.CreateNavigator.Select 快大约 0.5 倍。

    这些结论基于以下代码:

     [Test]
        public void CompareXPathNavigatorToXPathSelectElement()
        {     
            var max = 100000;
    
            Stopwatch watch = new Stopwatch();
            watch.Start();
    
            bool parseChildNodeValues = true;
    
            ParseUsingXPathNavigatorSelect(max, watch, parseChildNodeValues);
            ParseUsingXElementElements(watch, max, parseChildNodeValues);
            ParseUsingXElementXPathSelect(watch, max, parseChildNodeValues);
            ParseUsingXPathNavigatorFromXElement(watch, max, parseChildNodeValues);
        }
    
        private static void ParseUsingXPathNavigatorSelect(int max, Stopwatch watch, bool parseChildNodeValues)
        {
            var document = new XPathDocument(@"data\books.xml");
            var navigator = document.CreateNavigator();
    
            for (var i = 0; i < max; i++)
            {
                var books = navigator.Select("/catalog/book");
                while (books.MoveNext())
                {
                    var location = books.Current;
                    var book = new Book();
                    book.Id = location.GetAttribute("id", "");
    
                    if (!parseChildNodeValues) continue;
    
                    book.Title = location.SelectSingleNode("title").Value;
                    book.Genre = location.SelectSingleNode("genre").Value;
                    book.Price = location.SelectSingleNode("price").Value;
                    book.PublishDate = location.SelectSingleNode("publish_date").Value;
                    book.Author = location.SelectSingleNode("author").Value;
                }
            }
    
            watch.Stop();
            Console.WriteLine("Time using XPathNavigator.Select = " + watch.ElapsedMilliseconds);
        }
    
        private static void ParseUsingXElementElements(Stopwatch watch, int max, bool parseChildNodeValues)
        {
            watch.Restart();
            var element = XElement.Load(@"data\books.xml");
    
            for (var i = 0; i < max; i++)
            {
                var books = element.Elements("book");
                foreach (var xElement in books)
                {
                    var book = new Book();
                    book.Id = xElement.Attribute("id").Value;
    
                    if (!parseChildNodeValues) continue;
    
                    book.Title = xElement.Element("title").Value;
                    book.Genre = xElement.Element("genre").Value;
                    book.Price = xElement.Element("price").Value;
                    book.PublishDate = xElement.Element("publish_date").Value;
                    book.Author = xElement.Element("author").Value;
                }
            }
    
            watch.Stop();
            Console.WriteLine("Time using XElement.Elements = " + watch.ElapsedMilliseconds);
        }
    
        private static void ParseUsingXElementXPathSelect(Stopwatch watch, int max, bool parseChildNodeValues)
        {
            XElement element;
            watch.Restart();
            element = XElement.Load(@"data\books.xml");
    
            for (var i = 0; i < max; i++)
            {
                var books = element.XPathSelectElements("book");
                foreach (var xElement in books)
                {
                    var book = new Book();
                    book.Id = xElement.Attribute("id").Value;
    
                    if (!parseChildNodeValues) continue;
    
                    book.Title = xElement.Element("title").Value;
                    book.Genre = xElement.Element("genre").Value;
                    book.Price = xElement.Element("price").Value;
                    book.PublishDate = xElement.Element("publish_date").Value;
                    book.Author = xElement.Element("author").Value;
                }
            }
    
            watch.Stop();
            Console.WriteLine("Time using XElement.XpathSelectElement = " + watch.ElapsedMilliseconds);
        }
    
        private static void ParseUsingXPathNavigatorFromXElement(Stopwatch watch, int max, bool parseChildNodeValues)
        {
            XElement element;
            watch.Restart();
            element = XElement.Load(@"data\books.xml");
    
            for (var i = 0; i < max; i++)
            {
                // now we can use an XPath expression
                var books = element.CreateNavigator().Select("book");
    
                while (books.MoveNext())
                {
                    var location = books.Current;
                    var book = new Book();
                    book.Id = location.GetAttribute("id", "");
    
                    if (!parseChildNodeValues) continue;
    
                    book.Title = location.SelectSingleNode("title").Value;
                    book.Genre = location.SelectSingleNode("genre").Value;
                    book.Price = location.SelectSingleNode("price").Value;
                    book.PublishDate = location.SelectSingleNode("publish_date").Value;
                    book.Author = location.SelectSingleNode("author").Value;
                }
            }
    
            watch.Stop();
            Console.WriteLine("Time using XElement.Createnavigator.Select = " + watch.ElapsedMilliseconds);
        }
    

    带有从here下载的books.xml

    总体而言,XElement 解析 API(不包括 XPath 扩展)可以为您提供最佳性能,同时也更易于使用(如果您的文档有些扁平)。如果您有深层嵌套结构,您必须执行类似

    的操作
    XElement.Element("book").Element("author").Element("firstname").SomethingElse()
    

    那么 XElement.XPathSelectElement 可能会在性能和代码可维护性之间提供最佳折衷。

    【讨论】:

    • 我很好奇为什么您的结果没有表示为可读性的百分比变化?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-17
    • 1970-01-01
    • 2019-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多