Statically Compiled Queries (LINQ to XML)
One of the most important performance benefits LINQ to XML, as opposed to XmlDocument, is that queries in LINQ to XML are statically compiled, whereas XPath queries must be interpreted at run time. This feature is built in to LINQ to XML, so you do not have to perform extra steps to take advantage of it, but it is helpful to understand the distinction when choosing between the two technologies. This topic explains the difference.
Statically Compiled Queries vs. XPath
The following example shows how to get the descendant elements with a specified name, and with an attribute with a specified value.
The following is the equivalent XPath expression:
//Address[@Type='Shipping']
XDocument po = XDocument.Load("PurchaseOrders.xml");
IEnumerable<XElement> list1 =
from el in po.Descendants("Address")
where (string)el.Attribute("Type") == "Shipping"
select el;
foreach (XElement el in list1)
Console.WriteLine(el);
Dim po = XDocument.Load("PurchaseOrders.xml")
Dim list1 = From el In po.Descendants("Address")
Where el.@Type = "Shipping"
For Each el In list1
Console.WriteLine(el)
Next
The query expression in this example is re-written by the compiler to method-based query syntax. The following example, which is written in method-based query syntax, produces the same results as the previous one:
XDocument po = XDocument.Load("PurchaseOrders.xml");
IEnumerable<XElement> list1 =
po
.Descendants("Address")
.Where(el => (string)el.Attribute("Type") == "Shipping");
foreach (XElement el in list1)
Console.WriteLine(el);
Dim po = XDocument.Load("PurchaseOrders.xml")
Dim list1 As IEnumerable(Of XElement) = po.Descendants("Address").Where(Function(el) el.@Type = "Shipping")
For Each el In list1
Console.WriteLine(el)
Next
The Where method is an extension method. For more information, see Extension Methods (C# Programming Guide). Because Where is an extension method, the query above is compiled as though it were written as follows:
XDocument po = XDocument.Load("PurchaseOrders.xml");
IEnumerable<XElement> list1 =
System.Linq.Enumerable.Where(
po.Descendants("Address"),
el => (string)el.Attribute("Type") == "Shipping");
foreach (XElement el in list1)
Console.WriteLine(el);
Dim po = XDocument.Load("PurchaseOrders.xml")
Dim list1 = Enumerable.Where(po.Descendants("Address"), Function(el) el.@Type = "Shipping")
For Each el In list1
Console.WriteLine(el)
Next
This example produces exactly the same results as the previous two examples. This illustrates the fact that queries are effectively compiled into statically linked method calls. This, combined with the deferred execution semantics of iterators, improves performance. For more information about the deferred execution semantics of iterators, see Deferred Execution and Lazy Evaluation in LINQ to XML.
Note
These examples are representative of the code that the compiler might write. The actual implementation might differ slightly from these examples, but the performance will be the same or similar to these examples.
Executing XPath Expressions with XmlDocument
The following example uses XmlDocument to accomplish the same results as the previous examples:
XmlReader reader = XmlReader.Create("PurchaseOrders.xml");
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNodeList nl = doc.SelectNodes(".//Address[@Type='Shipping']");
foreach (XmlNode n in nl)
Console.WriteLine(n.OuterXml);
reader.Close();
Dim reader = Xml.XmlReader.Create("PurchaseOrders.xml")
Dim doc As New Xml.XmlDocument()
doc.Load(reader)
Dim nl As Xml.XmlNodeList = doc.SelectNodes(".//Address[@Type='Shipping']")
For Each n As Xml.XmlNode In nl
Console.WriteLine(n.OuterXml)
Next
reader.Close()
This query returns the same output as the examples that use LINQ to XML; the only difference is that LINQ to XML indents the printed XML, whereas XmlDocument does not.
However, the XmlDocument approach generally does not perform as well as LINQ to XML, because the SelectNodes method must do the following internally every time it is called:
It parses the string that contains the XPath expression, breaking the string into tokens.
It validates the tokens to make sure that the XPath expression is valid.
It translates the expression into an internal expression tree.
It iterates through the nodes, appropriately selecting the nodes for the result set based on the evaluation of the expression.
This is significantly more than the work done by the corresponding LINQ to XML query. The specific performance difference varies for different types of queries, but in general LINQ to XML queries do less work, and therefore perform better, than evaluating XPath expressions using XmlDocument.