เลือกองค์ประกอบ XML โดยไม่ใช้วิธีการขยาย

MSDN - ระบบ Xml.XPath Extensions Class พูดว่า:

มีโทษด้านประสิทธิภาพบางประการสำหรับการใช้วิธีการเหล่านี้ การใช้ LINQ กับแบบสอบถาม XML ให้ประสิทธิภาพที่ดีขึ้น

และ XPathSelectElement เป็นวิธีการขยาย

ฉันมี XML ต่อไปนี้ ฉันจำเป็นต้องค้นหาข้อความและเชื่อมต่อเข้าด้วยกัน ความท้าทายคือ - ฉันต้องเลือกเฉพาะข้อความที่อยู่ภายใต้ Status/StatusMsg/StatusDetail ด้วย Descendants ฉันได้รับข้อความทั้งหมด แม้จะอยู่นอกองค์ประกอบที่จำเป็นก็ตาม

ซึ่งสามารถทำได้อย่างถูกต้องโดยใช้ XPathSelectElement แต่เนื่องจาก XPathSelectElement เป็นวิธีส่วนขยาย จึงมีประสิทธิภาพบางอย่างดังที่แสดงใน LINQ to XML พร้อมการตรวจสอบประสิทธิภาพ XPath ซึ่งระบุว่า:

ในกรณีส่วนใหญ่ การเรียกใช้แบบสอบถาม XPath จะส่งผลให้มีระยะเวลาการดำเนินการนานกว่าการสืบค้นโดยใช้ LINQ มาตรฐานเป็น XML ถึง 5 เท่า

วิธีที่ดีที่สุดที่จะทำโดยไม่ใช้วิธีการขยายใน LINQ ถึง XML โดยใช้ C # คืออะไร

หมายเหตุ: มีวิธีปรับแต่ง 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());

person LCJ    schedule 21.03.2013    source แหล่งที่มา
comment
แทนเจนต์ แต่คำถามของคุณเกี่ยวข้องกับวิธีการขยายเพียงเล็กน้อยและเกี่ยวข้องกับ xpath มาก   -  person JerKimball    schedule 21.03.2013


คำตอบ (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 นั้นต้องทำลูกที่อยู่ติดกันขององค์ประกอบ

person Ryan Gates    schedule 21.03.2013
comment
มันไม่ได้คอมไพล์ - มีข้อความแสดงข้อผิดพลาดมา - 'string' ไม่มีคำจำกัดความสำหรับ 'IsNullOrWhitespace' มีความคิดอะไรบ้าง? หมายเหตุ: โครงการอยู่ใน .Net4.0 - person LCJ; 21.03.2013
comment
XPath ดูเหมือนจะเร็วกว่าการใช้ Descendants สองครั้ง มีความคิดว่าทำไม? ฉันได้อัปเดตคำถามแล้ว - person LCJ; 21.03.2013