¿Cuál es el mejor para el rendimiento: XPathNavigator con XPath vs Linq a Xml con consulta?

Tengo una aplicación en la que estoy usando XPathNavigator para iterar nodos. Está funcionando bien.

Pero quiero saber que si uso LINQ to Xml …

  1. ¿Qué beneficios (rendimiento, mantenibilidad) obtendré?

  2. Con XPath, LINQ to Xml, ¿cuál es el impacto del rendimiento?

Estoy usando C # .net, VS 2010 y mi .xml es de tamaño mediano.

Bueno, XPathNavigator generalmente será más rápido que Linq to XML consultas Linq to XML . Pero siempre hay ‘pero’.

Linq to XML definitivamente hará que su código sea más legible y mantenible. Es más fácil (al menos para mí) leer la consulta de linq y luego analizar XPath. Además, obtendrá una inteligencia al escribir consultas que ayudarán a corregir el código. Linq to XML también le ofrece la posibilidad de modificar fácilmente los datos, si eso es lo que necesita. XPathNavigator te da acceso de solo lectura.

Por otro lado, si realmente necesitas el mejor rendimiento, XPathNavigator es probablemente el camino a seguir. Simplemente depende de su situación actual y lo que está tratando de lograr. Si el rendimiento no es un problema (el archivo XML es bastante pequeño, no harás muchas solicitudes a este archivo, etc.) puedes ir fácilmente con Linq to XML . De lo contrario, quédate cerca de XPathNavigator .

Solo para agregar a lo que ya se ha indicado aquí, el rendimiento general parece depender de lo que realmente esté haciendo con el documento en cuestión. Esto es lo que he concluido basado en una ejecución experimental simple que compara el rendimiento del análisis entre XElement y XPathNavigator.

Si selecciona nodos, recorre estos nodos y lee algunos valores de atributo:

  • XElement.Element es más rápido que XElement.CreateNavigator.Seleccione por un factor aproximado de 1.5.
  • XElement.CreateNavigator.Select es más rápido que XPathNavigator.Seleccione por un factor aproximado de 0.5.
  • XPathNavigator.Select es más rápido que XElement.XPathSelectElement por un factor aproximado de 0.5.

Por otro lado, si también estás leyendo el valor de los hijos de cada nodo, se pone un poco interesante:

  • XElement.Element es más rápido que XElement.XPathSelectElements por un factor aproximado de 0.5.
  • XElement.XPathSelectElement es más rápido que XPathNavigator.Seleccione por un factor aproximado de 3.
  • XPathNavigator.Select es más rápido que XElement.CreateNavigator.Seleccione por un factor aproximado de 0.5.

Estas conclusiones se basan en el siguiente código:

  [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++) { // now we can use an XPath expression var books = element.CreateNavigator().Select("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 XElement.Createnavigator.Select = " + watch.ElapsedMilliseconds); } 

con books.xml descargado desde aquí

En general, parece que la API de análisis de XElement, excluyendo las extensiones XPath, le brinda el mejor rendimiento y, al mismo tiempo, es más fácil de usar, si su documento es algo plano. Si tienes estructuras anidadas profundas donde tienes que hacer algo como

 XElement.Element("book").Element("author").Element("firstname").SomethingElse() 

entonces XElement.XPathSelectElement puede proporcionar el mejor compromiso entre el rendimiento y la capacidad de mantenimiento del código.