2009-10-14 9 views
13

ich eine große Anzahl von großen Dateien bin Parsen und nach meinem Engpass Profilierungs ist:Wie zu bauen XmlNodes von XmlReader

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

Dieser Ansatz war sehr praktisch, weil ich Knoten wie folgt extrahieren könnte:

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

ich schalte auf XmlReader, aber wenn ich das Element finde ich brauche zu extrahieren ich in Bezug bin stecken, wie ein XmlNode von ihm als nicht allzu vertraut mit XmlReader zu bauen:

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? 
    } 
} 

Ich möchte in der Lage sein, ein List<XmlNode> Objekt zu bauen. Ich bin auf .NET 2.0.

Jede Hilfe wird geschätzt!

Antwort

6

Der Typ hat keinen öffentlichen Konstruktor, Sie können sie also nicht selbst erstellen. Sie werden ein XmlDocument haben müssen, dass Sie sie erstellen können:

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

scheint es leere Knoten zu erstellen? – JohnIdol

+0

Ja, es sei denn, Sie fügen etwas zu den Elementen hinzu (indem Sie der Eigenschaft 'InnerText' beispielsweise etwas zuweisen), sind sie leer. –

+0

oh yep - sieht jetzt offensichtlich aus, da ich gerade Elementnamen übergebe, danke – JohnIdol

5

XmlReader und XmlDocument eine sehr unterschiedliche Art und Weise der Verarbeitung haben. XmlReader speichert nichts im Speicher und verwendet einen Forward-Only-Ansatz im Gegensatz zum Erstellen eines vollständigen DOM-Baums im Speicher für XmlDocument. Dies ist hilfreich, wenn Leistung ein Problem ist, aber Sie müssen Ihre Anwendung auch anders schreiben: Anstatt zu verwenden, behalten Sie nichts und verarbeiten nur "von unterwegs": wenn ein Element an Ihnen vorbeikommt , du machst etwas. Dies ist nahe am SAX-Ansatz, jedoch ohne das Rückrufmodell.

Die Antwort auf "wie bekomme ich das XmlElement" lautet: Sie müssen sie basierend auf den Informationen aus dem Reader von Grund auf neu erstellen. Dies trotzt leider dem Leistungsgewinn. Es ist oft besser, die Verwendung von DOM-Ansätzen zu verhindern, wenn Sie einmal zu XmlReader wechseln, außer in einigen wenigen Fällen.

Auch die "sehr praktische" Möglichkeit, Knoten mit XPath zu extrahieren (SelectNodes ist das, was Sie oben zeigen) kann hier nicht verwendet werden: XPath benötigt eine DOM-Struktur. Betrachten Sie diesen Ansatz als Filtermethode: Sie können dem XmlReader Filter hinzufügen und ihn anweisen, bestimmte Knoten zu überspringen oder bis zu einem bestimmten Knoten zu lesen. Das ist extrem schnell, aber eine andere Art zu denken.

4

Verwenden Sie XmlDocument.ReadNode für diesen Ansatz. Setzen Sie XmlReader in die Anweisung und verwenden Sie XmlReader.LocalName anstelle von Name, um das Namespacepräfix zu entfernen.

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(); 
1

Ich habe die folgende Problemumgehung, wenn ich hatte einfügen Daten aus einem XmlReader in eine XmlDocumenht verwendet?

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

Warum nicht einfach wie folgt vor:

+0

Bereits beantwortet. Siehe http://stackoverflow.com/questions/1566192/how-to-build-xmlnodes-from-xmlreader/1566333#1566333. –

+0

Dies ist die richtige Antwort, da der andere leere Knoten enthält! –

0

Hier ist mein Ansatz:

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"})) 
{ 
    .... 
} 

Die Knoten können dann in ein anderes Dokument zur Weiterverarbeitung importiert werden.