3

MSDN - System.Xml.XPath Extensions Classは次のように述べています。

これらのメソッドを使用すると、パフォーマンスが低下します。LINQ to XML クエリを使用すると、パフォーマンスが向上します。

XPathSelectElementは拡張メソッドです

次の XML があります。メッセージを見つけて連結する必要があります。課題は、 に該当するメッセージのみを選択する必要があることStatus/StatusMsg/StatusDetailです。を使用Descendantsすると、必要な要素の外側であっても、すべてのメッセージを取得できます。

これは、 を使用して正しく実現できますXPathSelectElement。ただし、XPathSelectElement は拡張メソッドであるため、LINQ to XML with XPath のパフォーマンス レビューに示されているように、パフォーマンス ヒットがあります。

ほとんどの場合、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 を 2 回使用するよりも高速のようです。理由はありますか?

        // 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());
4

1 に答える 1

3

次のように、.Descendants (XName)ではなく.Elements(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

キーは、 xDocument が要素の直接の子を実行する必要がある検索を制限する.Elements(XName)を使用しているようです。

于 2013-03-21T04:33:59.693 に答える