【问题标题】:Select XML element without using Extension method选择 XML 元素而不使用扩展方法
【发布时间】:2013-03-26 15:27:13
【问题描述】:

MSDN - System.Xml.XPath Extensions Class 说:

使用这些方法会有一些性能损失。使用 LINQ to XML 查询会产生更好的性能。

XPathSelectElement是一种扩展方法

我有以下 XML。我需要找出消息并将其连接起来。挑战是 - 我只需要选择 Status/StatusMsg/StatusDetail 下的消息。使用Descendants,我收到了所有消息——甚至超出了必需的元素。

这可以使用XPathSelectElement 正确实现。但由于 XPathSelectElement 是一种扩展方法,它对性能有一定影响,如LINQ to XML with XPath performance review 所示:

在大多数情况下,运行 XPath 查询的执行时间是使用标准 LINQ to XML 查询的 5 倍。

不使用 C# 在 LINQ to XML 中使用扩展方法的最佳方法是什么?

注意:有没有办法为此目的调整Descendants

XML

XDocument xDoc = XDocument.Parse(@"  
          <Status>
                <StatusMsg>
                    <StatusType>INVOICE</StatusType>

                    <StatusDetail>
                        <Sequence test=""K"">  2  </Sequence>
                        <Message>A</Message>
                    </StatusDetail>

                    <StatusDetail>
                        <Message>B</Message>
                    </StatusDetail>

                    <StatusDetail>
                        <Message>C</Message>
                    </StatusDetail>
                </StatusMsg>

                    <StatusDetail>
                        <Message>OUTSIDE</Message>
                    </StatusDetail>
            </Status>
           ");

代码

// Descendants
var messageArrayWithOutside = xDoc.Descendants(@"StatusDetail")
                             .Select(
                                       x => x.Element("Message") == null ? String.Empty : x.Element("Message").Value.Trim()
                                    ).ToArray();

var textAll = string.Join(", ", messageArrayWithOutside);

//XPathSelectElements
var messageArray = xDoc.XPathSelectElements(@"Status/StatusMsg/StatusDetail")
                           .Select(
                                     x => x.Element("Message") == null ? String.Empty : x.Element("Message").Value.Trim()
                                  ).ToArray();

var text = string.Join(", ", messageArray);

更新

XPath 似乎比使用 Descendants 快两次。知道为什么吗?

        // Descendants
        Stopwatch stopWatchDescendants = new Stopwatch();
        stopWatchDescendants.Start();
        var messageArrayDecendants = xDoc.Descendants("StatusMsg")
            .Descendants("StatusDetail")
            .Select(
                x => x.Element("Message") == null ?string.Empty : x.Element("Message").Value.Trim()
            ).ToArray();

        var textDecendants = string.Join(", ", messageArrayDecendants);
        stopWatchDescendants.Stop();
        TimeSpan tsDescendants = stopWatchDescendants.Elapsed;


        //XPathSelectElements
        Stopwatch stopWatchXPath = new Stopwatch();
        stopWatchXPath.Start();
        var messageArrayXPath = xDoc.XPathSelectElements(@"Status/StatusMsg/StatusDetail")
                           .Select(
                                     x => x.Element("Message") == null ? String.Empty : x.Element("Message").Value.Trim()
                                  ).ToArray();

        var textXPath = string.Join(", ", messageArrayXPath);
        stopWatchXPath.Stop();
        TimeSpan tsXPath = stopWatchXPath.Elapsed;


        if (tsXPath > tsDescendants)
        {
            Console.WriteLine("LINQ is fast");
        }
        if (tsDescendants > tsXPath)
        {
            Console.WriteLine("XPath is fast");
        }

        Console.WriteLine("XPath :" + tsXPath.ToString());
        Console.WriteLine("LINQ :" + tsDescendants.ToString());

【问题讨论】:

  • Tangent,但你的问题与扩展方法关系不大,与 xpath 关系很大。

标签: c# xml linq


【解决方案1】:

您需要使用.Elements(XName) 而不是.Descendants(XName),如下所示:

var messageArrayWithOutside = xDoc.Elements("StatusMsg")
    .Elements("StatusDetail")
    .Select(
        x => 
            x.Element("Message") == null ? 
            string.Empty : 
            x.Element("Message").Value.Trim()
    ).ToArray();

var textAll = string.Join(", ", messageArrayWithOutside);

然后 textAll 字符串将包含所需的输出并省略 OUTSIDE:

A, B, C

关键似乎是使用.Elements(XName),这限制了 xDocument 必须执行元素的直接子元素的搜索。

【讨论】:

  • 它无法编译 - 出现错误消息 - 'string' 不包含 'IsNullOrWhitespace' 的定义。任何想法?注:项目在.Net4.0
  • XPath 似乎比使用 Descendants 两次要快。知道为什么吗?我已经更新了问题
猜你喜欢
  • 2010-12-02
  • 1970-01-01
  • 1970-01-01
  • 2011-03-29
  • 2015-10-13
  • 2020-06-19
  • 2012-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多