2009-09-28 12 views
6

Tengo una cadena que contiene xml bien formado. Quiero navegar el XML en esa cadena para extraer el texto en ciertos nodos. ¿Cómo puedo lograr esto de manera eficiente usando una clase .NET incorporada? ¿Qué clase de XML .NET usarías y por qué?¿Manera eficiente de construir un documento XML a partir de una cadena que contiene XML bien formado para la navegación?

Muchas gracias por su ayuda.

Nota 1: Linq no está disponible para mí. Nota 2: Editar el XML no es importante. El acceso de solo lectura es lo que necesito.

Respuesta

10

Para la velocidad, use un XmlReader:

using (StringReader sr = new StringReader(myString)) 
using (XmlReader xr = XmlReader.Create(sr)) 
{ 
    while (xr.Read()) 
    { 
     if (xr.NodeType == XmlNodeType.Element && xr.Name == "foo") 
     { 
      Console.WriteLine(xr.ReadString()); 
     } 
    } 
} 

Las impresiones anteriores fuera el contenido del texto de cada elemento llamado "foo" en el documento XML. (. Bueno, más o menos ReadString no maneja elementos anidados con mucha gracia.)

El uso de un XPathDocument es más lento, porque todo el documento se analiza antes de poder iniciar la búsqueda, pero tiene el mérito de la simplicidad:

using (StringReader sr = new StringReader(myString)) 
{ 
    XPathDocument d = new XPathDocument(sr); 
    foreach (XPathNavigator n in d.CreateNavigator().Select("//foo/text()")) 
    { 
     Console.WriteLine(n.Value); 
    } 
} 

Si usted no está preocupado con el rendimiento o utilización de la memoria, que es más sencilla de usar un XmlDocument:

XmlDocument d = new XmlDocument(); 
d.LoadXml(myString); 
foreach (XmlNode n in d.SelectNodes("//foo/text()")) 
{ 
    Console.WriteLine(n.Value); 
} 
+1

Buena respuesta con muestras de código. Como nota al margen, 'XPathNodeIterator' implementa' IEnumerable', por lo que no es necesario usar 'while' -' foreach' hará el truco también, y es más fácil de leer. –

+0

Tienes razón; Edité el ejemplo para mostrar eso. –

3

Usaría XmlDocument.Load() para obtener un DOM de la cadena. Luego puede recorrerlo usando los métodos DOM apropiados o XPATH según sea necesario.

3

Depende de la estructura de XML. Si es relativamente simple, entonces la forma más eficiente de envolver la cadena en StringReader, y luego envolver eso en XmlReader. El beneficio es que no tendrá que crear un árbol XML en la memoria, copiar datos de la cadena; simplemente leerá los nodos uno por uno.

Si la estructura del documento es lo suficientemente complicada, es posible que necesite (o desee) un DOM - en cuyo caso XDocument.Parse debería ser el truco.

+0

Su sonido como una buena idea, pero no tengo acceso a LINQ. – Newbie

+0

No veo el punto de envolverlo dentro de un StringReader. Por lo que yo sé, el único propósito de StringReader es tener cadenas mutables de modo que cuando se realizan muchas operaciones de cadena. La sobrecarga de crear nuevas cadenas para cada manipulación de cadena ha desaparecido con StringReader. No veo cómo encaja eso aquí? – Henri

+1

@Henry: Estás confundiendo 'StringWriter' con' StringReader'. 'StringReader' se usa aquí para proporcionar la interfaz' TextReader' sobre una cadena simple, porque 'XmlReader.Create' espera' TextReader'. –

7

¿Para la navegación? Probablemente XPathDocument:

string s = @"<xml/>"; 
XPathDocument doc = new XPathDocument(new StringReader(s)); 

De MSDN,

Proporciona una, de sólo lectura, en memoria rápida representación de un documento XML utilizando el modelo de datos XPath.

diferencia de XmlDocument etc, está optimizado para el uso de sólo lectura; más eficiente pero menos poderoso (es decir, no puede editarlo). Para notas sobre cómo consultarlo, see here.

+2

Se debe tener en cuenta que 'XPathDocument' es realmente _significativamente más rápido en algunos tipos de consultas XPath; notablemente cualquier cosa que involucre el eje 'anterior' o 'anterior-hermano'. –

+0

Tenga en cuenta que no ha llamado a Dispose() en el StringReader que creó en este ejemplo. Vea la respuesta aceptada por Robert Rossney. – ALEXintlsos

+0

@ALEXintlsos no me malinterpreten: normalmente soy excepcionalmente pedante sobre 'IDisposable'; pero: 'StringReader' es solo uno de esos casos en los que * realmente, realmente * no va a importar. ¿Es más correcto desecharlo? Por supuesto. ¿Importará * alguna vez, de * cualquier * manera? Nop; p –

Cuestiones relacionadas