2009-09-28 9 views
6

Ho una stringa che contiene xml ben formato. Voglio navigare l'XML in quella stringa per estrarre il testo in determinati nodi. Come faccio a farlo in modo efficiente usando una classe .NET integrata. Quale classe XML di XML useresti e perché?Modo efficiente di costruire un documento XML da una stringa contenente XML ben formato per la navigazione?

Molte grazie per il vostro aiuto.

Nota 1: Linq non è disponibile per me. Nota 2: la modifica dell'XML non è importante. L'accesso in sola lettura è ciò di cui ho bisogno.

risposta

10

Per la velocità, utilizzare 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()); 
     } 
    } 
} 

Le stampe precede rispecchia il contenuto del testo di ogni elemento di nome "pippo" nel documento XML. (. Beh, sorta di ReadString non gestisce elementi annidati molto garbo.)

Utilizzando un XPathDocument è più lento, perché l'intero documento viene analizzato prima di poter avviare la ricerca di esso, ma ha il pregio della semplicità:

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

Se non sei interessati con le prestazioni o l'utilizzo della memoria, è più semplice utilizzare un XmlDocument:

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

Bella risposta con esempi di codice. Come nota a margine, 'XPathNodeIterator' implementa' IEnumerable', quindi non c'è bisogno di usare 'while' -' foreach' farà anche il trucco, ed è più facile da leggere. –

+0

Giusto sei; Ho modificato l'esempio per dimostrarlo. –

3

Vorrei utilizzare XmlDocument.Load() per ottenere un DOM dalla stringa. Quindi puoi attraversarlo usando i metodi DOM appropriati o XPATH se necessario.

3

Dipende dalla struttura di XML. Se è relativamente semplice, il modo più efficace per avvolgere la stringa in StringReader e quindi includerla in XmlReader. Il vantaggio è che non sarà necessario creare un albero XML in memoria, copiando i dati dalla stringa: basta leggere i nodi uno per uno.

Se la struttura del documento è abbastanza complicata, potrebbe essere necessario (o volere) un DOM - nel qual caso XDocument.Parse dovrebbe fare il trucco.

+0

vostro suono come una buona idea, ma non ho accesso a LINQ. – Newbie

+0

Non vedo il punto nel wrapping all'interno di un StringReader. Per quanto ne so, l'unico scopo di StringReader è di avere stringhe mutabili tali che quando vengono eseguite molte operazioni con le stringhe. L'overhead della creazione di nuove stringhe per ogni manipolazione di stringhe è finito con StringReader. Non vedo come si adatta qui? – Henri

+1

@Henry: stai confondendo 'StringWriter' con' StringReader'. 'StringReader' è usato qui per fornire l'interfaccia' TextReader' su una stringa semplice, perché 'XmlReader.Create' si aspetta' TextReader'. –

7

Per la navigazione? Probabilmente XPathDocument:

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

da MSDN,

Fornisce un veloce, di sola lettura, in memoria rappresentazione di un documento XML utilizzando il modello di dati XPath.

A differenza di XmlDocument ecc., È ottimizzato per l'utilizzo di sola lettura; più efficiente ma meno potente (cioè non puoi modificarlo). Per le note su come interrogarlo, see here.

+2

Si noti che 'XPathDocument' è in realtà _significantly_ più veloce su alcuni tipi di query XPath; in particolare tutto ciò che riguarda l'asse 'previous' o' previous-sibling'. –

+0

Ricorda che non hai chiamato Dispose() su StringReader che hai creato in questo esempio. Vedi la risposta accettata di Robert Rossney. – ALEXintlsos

+0

@ALEXintlsos non mi sbagliano: normalmente sono eccezionalmente pedante su 'IDisposable'; ma: 'StringReader' è solo uno di quei casi in cui * davvero, davvero * non ha importanza. È più corretto disporlo? sicuro. * * Mai * importa, in * qualsiasi * modo? No; p –

Problemi correlati