2013-03-21 3 views
3

MSDN - System.Xml.XPath Extensions Class говорит:Выберите XML элемент без использования метода расширения

Существует некоторая производительность штраф за использование этих методов. Использование запросов LINQ to XML обеспечивает лучшую производительность.

И XPathSelectElement является метод расширения

я следующий XML. Мне нужно узнать сообщения и объединить их. Проблема в том, что мне нужно выбрать только сообщения, которые попадают под Status/StatusMsg/StatusDetail. С Descendants, я получаю все сообщения - даже вне необходимых элементов.

Этого можно достичь с помощью XPathSelectElement. Но поскольку XPathSelectElement является метод расширения, он имеет некоторое падение производительности, как показано на LINQ to XML with XPath performance review, который говорит:

В большинстве случаев, где выполняется запрос XPath приведет в 5 раз больше периода выполнения, чем запрос с использованием стандартного LINQ к XML.

Каков наилучший способ сделать это без использования метода расширения в LINQ to 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); 

UPDATE

XPath, кажется, быстрее, чем при использовании потомках два раза. Любая идея почему?

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

Tangent, но ваш вопрос имеет мало общего с методами расширения и многое, что связано с xpath. – JerKimball

ответ

3

Вы должны использовать .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 должен выполнять для непосредственных детей элемента.

+0

Не компилируется - появляется сообщение об ошибке - «строка» не содержит определения для «IsNullOrWhitespace». Есть идеи? Примечание. Проект находится в .Net4.0 – Lijo

+0

XPath кажется более быстрым, чем использование потомков два раза. Любая идея почему? Я обновил вопрос – Lijo

+1

@ Lijo У меня была лучшая производительность с помощью .Elements –

Смежные вопросы