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>
");
CODE
// 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());
答案 0 :(得分: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必须对元素的直接子项进行的搜索。