2015-01-27 13 views
6

Sto tentando di elaborare un documento XML di grandi dimensioni (utilizzando un XmlReader) in un unico passaggio e deserializzare solo alcuni elementi in esso utilizzando un XmlSerializer.Deserializzazione di un singolo elemento in un documento XML di grandi dimensioni: xmlSerializer.Deserialize (xmlReader.ReadSubtree()) non riesce a causa dei problemi dello spazio dei nomi

Di seguito è riportato un codice e un piccolo documento XML fittizio che mostra come ho tentato di farlo.

razionale per l'utilizzo XmlReader:1. ho a che fare con i documenti di grandi dimensioni XML (10 – 250 MB), che per questo motivo non voglio caricare in memoria. Quindi XmlDocument è fuori questione. 2. Voglio estrarre solo determinati elementi. In genere potrò ignorare la maggior parte degli altri contenuti. XmlReader sembra darmi un mezzo efficace per ignorare i contenuti irrilevanti. 3. Non so in anticipo se saranno presenti tutti gli elementi che posso trattare; quindi non sto usando un mucchio di Xpath/XQuery o LINQ alle query basate su XML, perché voglio fare solo un passaggio sui file XML (a causa delle loro dimensioni).

public class ElementOfInterest { } 
… 

var xml = @"<?xml version='1.0' encoding='utf-8' ?> 
      <Root xmlns:ex='urn:stakx:example' 
        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'> 
       <ElementOfInterest xsi:type='ex:ElementOfInterest' /> 
      </Root>"; 

var reader = System.Xml.XmlReader.Create(new System.IO.StringReader(xml)); 
reader.ReadToFollowing("ElementOfInterest"); 

var serializer = new System.Xml.Serialization.XmlSerializer(typeof(ElementOfInterest)); 
serializer.Deserialize(reader.ReadSubtree()); 

L'ultima riga di codice genera la seguente eccezione interna:

InvalidOperationException: "prefisso namespace ex non è definito."

Ovviamente, il XmlSerializer non riconosce il prefisso ex namespace all'interno il valore dell'attributo xsi:type.

Questo è solo un errore che sto avendo, ma francamente, il problema più grande è che non ho idea di come andare sull'intero problema dello spazio dei nomi. Sto semplicemente cercando un modo conveniente per de-serializzare solo un singolo nodo dal documento XML, ma questo sembra implicare la necessità di registrare/gestire manualmente gli spazi dei nomi e in qualche modo inoltrarli dallo XmlReader allo XmlSerializer.

Qualcuno può dimostrare come deserializzare un singolo nodo da un documento XML letto con uno XmlReader, indicando l'errore nel mio codice o mostrando un approccio alternativo?

+3

Cercare un esempio su 'XmlNamespaceManager'. Ecco [uno] (http://stackoverflow.com/a/14462578/815938) per iniziare. – kennyzx

+0

@kennyzx: ho esaminato 'XmlNamespaceManager' e' XmlNameTable' e 'XmlParserContext', e cosa no. Semplicemente non ho idea di come si debba incastrare nel mio scenario. Potresti manifestare il suo uso per me? – stakx

risposta

5

le seguenti opere:

using System.IO; 
using System.Xml; 
using System.Xml.Serialization; 

static void Main() 
{ 
    var xml = @"<?xml version='1.0' encoding='utf-8' ?> 
       <Root 
        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' 
        xmlns:ex='urn:stakx:example' 
       > 
        <ex:ElementOfInterest xsi:type='ex:ElementOfInterest' /> 
       </Root>"; 

    var nt = new NameTable(); 
    var mgr = new XmlNamespaceManager(nt); 
    mgr.AddNamespace("ex", "urn:stakx:example"); 
    var ctxt = new XmlParserContext(nt, mgr, "", XmlSpace.Default); 
    var reader = XmlReader.Create(new StringReader(xml), null, ctxt); 
    var serializer = new XmlSerializer(typeof(ElementOfInterest)); 

    reader.ReadToFollowing("ElementOfInterest", "urn:stakx:example"); 
    var eoi = (ElementOfInterest)serializer.Deserialize(reader.ReadSubtree()); 
} 

[XmlRoot(Namespace = "urn:stakx:example")] 
public class ElementOfInterest { } 

Nota lo spazio dei nomi in entrata: <ex:ElementOfInterest>.

+0

Puoi spiegare perché hai modificato il documento di input (ad esempio, hai aggiunto il prefisso dello spazio dei nomi all'elemento)? È per far funzionare il tuo codice, o perché * la mia * versione dell'input di esempio non è stata ben strutturata/non valida in qualche modo? – stakx

+1

Entrambi, una specie di.Bene, il tuo documento di input afferma che l'oggetto risultante dovrebbe trovarsi nello spazio dei nomi 'urna: stakx: example'. La tua classe di destinazione 'ElementOfInterest' non riflette questo, quindi aggiungere l'attributo di classe' XmlRoot (Namespace = ...) 'è stato il primo cambiamento. Ora, quando si * serializza * un oggetto 'ElementOfInterest', l'elemento XML risultante si troverà anche nello spazio dei nomi' urna: stakx: example'. Per rendere la deserializzazione e la serializzazione simmetriche, ho dovuto inserire l'elemento in quello spazio dei nomi nell'input. – Tomalak

Problemi correlati