Pilih elemen XML tanpa menggunakan metode Ekstensi

MSDN - System.out. Kelas Ekstensi Xml.XPath mengatakan:

Ada beberapa penalti kinerja untuk menggunakan metode ini. Menggunakan kueri LINQ ke XML menghasilkan kinerja yang lebih baik.

Dan XPathSelectElement adalah metode ekstensi

Saya telah mengikuti XML. Saya perlu mencari tahu pesan-pesannya dan menggabungkannya. Tantangannya adalah - saya hanya perlu memilih pesan yang berada di bawah Status/StatusMsg/StatusDetail. Dengan Descendants, saya menerima semua pesan - bahkan di luar elemen yang diperlukan.

Ini dapat dicapai dengan benar menggunakan XPathSelectElement. Namun karena XPathSelectElement adalah metode ekstensi, kinerjanya mengalami peningkatan seperti yang ditunjukkan di LINQ ke XML dengan tinjauan kinerja XPath yang menyatakan:

Dalam kebanyakan kasus, menjalankan kueri XPath akan menghasilkan periode eksekusi 5 kali lebih lama dibandingkan kueri menggunakan LINQ standar ke XML.

Apa cara terbaik untuk melakukannya tanpa menggunakan metode ekstensi di LINQ ke XML menggunakan C#?

Catatan: Apakah ada cara untuk mengubah Descendants untuk tujuan ini?

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>
           ");

KODE

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

PEMBARUAN

XPath tampaknya lebih cepat daripada menggunakan Descendants dua kali. Tahu kenapa?

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

person LCJ    schedule 21.03.2013    source sumber
comment
Singgung, tetapi pertanyaan Anda tidak ada hubungannya dengan metode ekstensi dan banyak hubungannya dengan xpath.   -  person JerKimball    schedule 21.03.2013


Jawaban (1)


Anda perlu menggunakan .Elements(XName) daripada .Descendants(XName) seperti berikut:

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

String textAll kemudian akan berisi output yang diinginkan dan menghilangkan OUTSIDE:

A, B, C

Kuncinya tampaknya menggunakan .Elements(XName) yang membatasi pencarian xDocument itu harus mengerjakan turunan langsung dari elemen tersebut.

person Ryan Gates    schedule 21.03.2013
comment
Itu tidak dapat dikompilasi - pesan kesalahan muncul - 'string' tidak mengandung definisi untuk 'IsNullOrWhitespace'. Ada ide? Catatan: Proyek ini dalam .Net4.0 - person LCJ; 21.03.2013
comment
XPath tampaknya lebih cepat daripada menggunakan Descendants dua kali. Tahu kenapa? Saya telah memperbarui pertanyaannya - person LCJ; 21.03.2013