哪种性能最好:使用 XPath 的 XPathNavigator 与使用查询的 Linq to Xml?

发布于 2024-12-21 07:11:22 字数 223 浏览 3 评论 0原文

我有一个应用程序,在其中使用 XPathNavigator 来迭代节点。它运行良好。

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

  1. 我会得到什么好处(性能、可维护性)?

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

我正在使用 C#.net、VS 2010,我的 .xml 是中等大小。

I have an application in which I am using XPathNavigator to iterate nodes. It is working fine.

But I want to know that if I use LINQ to Xml....

  1. What benefits(Performance, maintainability) I will get?

  2. With XPath, LINQ to Xml what is the performance hit?

I am using C#.net, VS 2010 and my .xml is mid size.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

給妳壹絲溫柔 2024-12-28 07:11:22

只是补充一下这里已经说过的内容,整体性能似乎取决于您对相关文档的实际操作。这是我根据比较 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);
    }

使用从 这里

总体而言,看起来 XElement 解析 API(不包括 XPath 扩展)可以为您提供最佳性能,同时如果您的文档有点 平坦的。如果您有深层嵌套结构,您必须执行类似的操作

XElement.Element("book").Element("author").Element("firstname").SomethingElse()

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

Just to add onto what has already been stated here, overall performance seems to depends on what you are actually doing with the document in question. This is what I have concluded based on a simple experimental run comparing parsing performance between XElement to XPathNavigator.

If you are selecting nodes, traversing these nodes and reading some attribute values:

  • XElement.Element is faster than XElement.CreateNavigator.Select by an
    approximate factor of 1.5.
  • XElement.CreateNavigator.Select is faster
    than XPathNavigator.Select by an approximate factor of 0.5.
  • XPathNavigator.Select is faster than XElement.XPathSelectElement by
    an approximate factor of 0.5.

On the other hand, if you are also reading the value of each node's children it gets a little interesting:

  • XElement.Element is faster than XElement.XPathSelectElements by an approximate factor of 0.5.
  • XElement.XPathSelectElement is faster than XPathNavigator.Select by an approximate factor of 3.
  • XPathNavigator.Select is faster than XElement.CreateNavigator.Select by an approximate factor of 0.5.

These conclusions are based on the following code:

 [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);
    }

with books.xml downloaded from here

Overall, it looks like the XElement parsing API, excluding the XPath extensions, gives you the best performance, while also easier to use, if your document is somewhat flat. If you have deep nested structures where you have to do something like

XElement.Element("book").Element("author").Element("firstname").SomethingElse()

then XElement.XPathSelectElement may provide the best compromise between performance and code maintainability.

小…楫夜泊 2024-12-28 07:11:22

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

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

另一方面,如果您确实需要顶级性能,XPathNavigator 可能是最佳选择。这仅取决于您当前的情况以及您想要实现的目标。如果性能不是问题(XML 文件相当小,您不会对此文件发出很多请求等等),您可以轻松使用 Linq to XML。否则请密切关注 XPathNavigator

Well, XPathNavigator will generally be faster than Linq to XML queries. But there's always 'but'.

Linq to XML will definitely make your code more readable and maintainable. It's easier (at least for me) to read linq query then analyze XPath. Also - you will get intellisense when writing query which will help to make your code correct. Linq to XML also gives you possibility to easily modify data, if that's what you need. XPathNavigator gives you readonly access.

On the other hand, if you really need top performance, XPathNavigator is probably the way to go. It simply depends on your current scenario and what you're trying to accomplish. If performance is not an issue (XML file is rather small, you won't make many requests to this file and so on) you can easily go with Linq to XML. Otherwise stick close to XPathNavigator.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文