To add to what has already been said here, overall performance seems to depend on what you are actually doing with the document in question. This is what I did based on a simple experimental run comparing the parsing performance between XElement and XPathNavigator.
If you select nodes, bypass these nodes and read some attribute values:
- XElement.Element is faster than XElement.CreateNavigator.Select with an approximate ratio of 1.5.
- XElement.CreateNavigator.Select is faster than XPathNavigator. Choose an approximate factor of 0.5.
- XPathNavigator.Select is faster than XElement.XPathSelectElement by an approximate factor of 0.5.
On the other hand, if you also read the meaning of each of the node children, it becomes a little interesting:
- XElement.Element is faster than XElement.XPathSelectElements with an approximate coefficient of 0.5.
- XElement.XPathSelectElement is faster than XPathNavigator. Select an approximate factor of 3.
- XPathNavigator.Select is faster than XElement.CreateNavigator.Select by about 0.5.
These findings are based on the following code:
[Test] public void CompareXPathNavigatorToXPathSelectElement() { var max = 100000; Stopwatch watch = new Stopwatch(); watch.Start(); bool parseChildNodeValues = true; ParseUsingXPathNavigatorSelect(max, watch, parseChildNodeValues); ParseUsingXElementElements(watch, max, parseChildNodeValues); ParseUsingXElementXPathSelect(watch, max, parseChildNodeValues); ParseUsingXPathNavigatorFromXElement(watch, max, parseChildNodeValues); } private static void ParseUsingXPathNavigatorSelect(int max, Stopwatch watch, bool parseChildNodeValues) { var document = new XPathDocument(@"data\books.xml"); var navigator = document.CreateNavigator(); for (var i = 0; i < max; i++) { var books = navigator.Select("/catalog/book"); while (books.MoveNext()) { var location = books.Current; var book = new Book(); book.Id = location.GetAttribute("id", ""); if (!parseChildNodeValues) continue; book.Title = location.SelectSingleNode("title").Value; book.Genre = location.SelectSingleNode("genre").Value; book.Price = location.SelectSingleNode("price").Value; book.PublishDate = location.SelectSingleNode("publish_date").Value; book.Author = location.SelectSingleNode("author").Value; } } watch.Stop(); Console.WriteLine("Time using XPathNavigator.Select = " + watch.ElapsedMilliseconds); } private static void ParseUsingXElementElements(Stopwatch watch, int max, bool parseChildNodeValues) { watch.Restart(); var element = XElement.Load(@"data\books.xml"); for (var i = 0; i < max; i++) { var books = element.Elements("book"); foreach (var xElement in books) { var book = new Book(); book.Id = xElement.Attribute("id").Value; if (!parseChildNodeValues) continue; book.Title = xElement.Element("title").Value; book.Genre = xElement.Element("genre").Value; book.Price = xElement.Element("price").Value; book.PublishDate = xElement.Element("publish_date").Value; book.Author = xElement.Element("author").Value; } } watch.Stop(); Console.WriteLine("Time using XElement.Elements = " + watch.ElapsedMilliseconds); } private static void ParseUsingXElementXPathSelect(Stopwatch watch, int max, bool parseChildNodeValues) { XElement element; watch.Restart(); element = XElement.Load(@"data\books.xml"); for (var i = 0; i < max; i++) { var books = element.XPathSelectElements("book"); foreach (var xElement in books) { var book = new Book(); book.Id = xElement.Attribute("id").Value; if (!parseChildNodeValues) continue; book.Title = xElement.Element("title").Value; book.Genre = xElement.Element("genre").Value; book.Price = xElement.Element("price").Value; book.PublishDate = xElement.Element("publish_date").Value; book.Author = xElement.Element("author").Value; } } watch.Stop(); Console.WriteLine("Time using XElement.XpathSelectElement = " + watch.ElapsedMilliseconds); } private static void ParseUsingXPathNavigatorFromXElement(Stopwatch watch, int max, bool parseChildNodeValues) { XElement element; watch.Restart(); element = XElement.Load(@"data\books.xml"); for (var i = 0; i < max; i++) {
with books.xml downloaded from here
All in all, it seems that the XElement analysis API, excluding XPath extensions, gives you better performance and is also easier to use if your document is somewhat flat. If you have deep nested structures where you need to do something like
XElement.Element("book").Element("author").Element("firstname").SomethingElse()
then XElement.XPathSelectElement can provide a better compromise between performance and code support.