2009-10-14 16 views
13

estoy analizar un gran número de archivos de gran tamaño y después de perfilar mi cuello de botella es:Cómo construir XMLNodes de XmlReader

XmlDocument doc = new XmlDocument(); 
doc.Load(filename); 

Este enfoque fue muy útil porque podía extraer nodos de la siguiente manera:

XmlNodeList nodeList = doc.SelectNodes("myXPath"); 

estoy cambiando a XmlReader, pero cuando encuentro el elemento que necesito para extraer estoy atascado con respecto a cómo construir un XmlNode de ella como no demasiado familiarizados con XmlReader:

XmlReader xmlReader = XmlReader.Create(fileName); 

while (xmlReader.Read()) 
{ 
    //keep reading until we see my element 
    if (xmlReader.Name.Equals("myElementName") && (xmlReader.NodeType == XmlNodeType.Element)) 
    { 
     // How do I get the Xml element from the reader here? 
    } 
} 

Me gustaría poder construir un objeto List<XmlNode>. Estoy en .NET 2.0.

Cualquier ayuda apreciada!

Respuesta

6

El tipo XmlNode no tiene un constructor público, por lo que no puede crearlos por su cuenta. Usted necesita tener una XmlDocument que se puede utilizar para crearlos:

XmlDocument doc = new XmlDocument(); 
while (xmlReader.Read()) 
{ 
    //keep reading until we see my element 
    if (xmlReader.Name.Equals("myElementName") && (xmlReader.NodeType == XmlNodeType.Element)) 
    { 
     // How do I get the Xml element from the reader here? 
     XmlNode myNode = doc.CreateNode(XmlNodeType.Element, xmlReader.Name, ""); 
     nodeList.Add(myNode); 
    }   
} 
+1

Parece que está creando nodos vacíos? – JohnIdol

+0

Sí, a menos que agregue algo a los elementos (asignando algo a la propiedad 'InnerText' por ejemplo) estarán vacíos. –

+0

oh sí - parece obvio ahora ya que solo estoy pasando el nombre del elemento, gracias – JohnIdol

5

XmlReader y XmlDocument tienen una forma muy distinta de procesamiento. XmlReader no guarda nada en la memoria y utiliza un enfoque directo solo en lugar de construir un árbol DOM completo en memoria para XmlDocument. Es útil cuando el rendimiento es un problema, pero también requiere que escriba su aplicación de manera diferente: en lugar de usar XmlNode, no guarda nada y solo procesa "sobre la marcha": es decir, cuando pasa un elemento que necesita haces algo Esto está cerca del enfoque SAX, pero sin el modelo de devolución de llamada.

La respuesta a "cómo obtener el XmlElement" es: tendrá que compilar desde cero en función de la información del lector. Desafortunadamente, esto desafía la ganancia de rendimiento. A menudo es mejor evitar el uso de enfoques DOM por completo una vez que cambie a XmlReader, a menos que sea por unos pocos casos distintos.

Además, la forma "muy práctica" de extraer nodos usando XPath (SelectNodes es lo que se muestra arriba) no se puede usar aquí: XPath requiere un árbol DOM. Considere este enfoque como un enfoque de filtrado: puede agregar filtros al XmlReader y decirle que omita ciertos nodos o que los lea hasta cierto nodo. Esto es extremadamente rápido, pero una forma diferente de pensar.

4

Utilice XmlDocument.ReadNode para este enfoque. Ponga XmlReader en la instrucción using y use XmlReader.LocalName en lugar de Name para eliminar el prefijo del espacio de nombres.

1

He utilizado el siguiente solución cuando he tenido que insertar datos de un XmlReader en un XmlDocumenht:

XmlReader rdr = cmd.ExecuteXmlReader(); 

XmlDocument doc = new XmlDocument(); 

// create a container node for our resultset 
XmlElement root = doc.CreateElement("QueryRoot"); 
doc.AppendChild(root); 

StringBuilder xmlBody = new StringBuilder(); 

while(rdr.Read()) 
{ 
    xmlBody.Append(rdr.ReadOuterXml()); 
} 

root.InnerXml = xmlBody.ToString(); 
12

¿Por qué no haga lo siguiente?

XmlDocument doc = new XmlDocument(); 
XmlNode node = doc.ReadNode(reader); 
+0

Ya respondido. Consulte http://stackoverflow.com/questions/1566192/how-to-build-xmlnodes-from-xmlreader/1566333#1566333. –

+0

¡Esta es la respuesta correcta ya que la otra deja nodos en blanco! –

0

Aquí es mi enfoque:

public static IEnumerable<XmlNode> StreamNodes(
    string path, 
    string[] tagNames) 
{    
    var doc = new XmlDocument();    
    using (XmlReader xr = XmlReader.Create(path)) 
    { 
     xr.MoveToContent(); 
     while (true) { 
      if (xr.NodeType == XmlNodeType.Element && 
       tagNames.Contains(xr.Name)) 
      { 
       var node = doc.ReadNode(xr); 
       yield return node; 
      } 
      else 
      { 
       if (!xr.Read()) 
       { 
        break; 
       } 
      } 
     } 
     xr.Close(); 
    }       
} 
// Used like this: 
foreach (var el in StreamNodes("orders.xml", new string[]{"order"})) 
{ 
    .... 
} 

Los nodos se pueden importar en otro documento para su posterior procesamiento.