2015-01-27 10 views
6

Próbuję przetworzyć duży dokument XML (używając XmlReader) w jednym przebiegu i deserializować tylko niektóre elementy w nim za pomocą XmlSerializer.Usuwanie pojedynczego elementu z dużego dokumentu XML: xmlSerializer.Deserialize (xmlReader.ReadSubtree()) kończy się niepowodzeniem z powodu problemów z obszarami nazw

Poniżej znajduje się kod i mały, fałszywy dokument XML pokazujący, w jaki sposób próbowałem to zrobić.

uzasadnienie dla korzystania XmlReader:1. mam do czynienia z bardzo dużych dokumentów XML (10 – 250 MB), które z tego powodu nie chcę, aby załadować do pamięci. Tak więc XmlDocument jest wykluczone. 2. Chcę wyodrębnić tylko niektóre elementy. Zazwyczaj będę mógł zignorować większość innych treści. XmlReader wydaje mi się skutecznym sposobem na pomijanie nieistotnych treści. 3. Nie wiem z góry, czy będą obecne wszystkie elementy, z którymi będę mógł sobie poradzić; w związku z tym nie używam kilka z Xpath/XQuery lub LINQ do kwerend opartych na XML, ponieważ chcę zrobić tylko jedno przejście przez pliki XML (ze względu na ich rozmiar).

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

Ostatnia linia kodu generuje po wewnętrznej wyjątek:

InvalidOperationException: "Namesepace prefiks ex nie jest zdefiniowana"

Oczywiście XmlSerializer nie rozpoznaje namespace prefix ex wewnątrz wartości atrybutu xsi:type.

To tylko jeden błąd, jaki mam, ale prawdę mówiąc, większy problem polega na tym, że nie mam pojęcia, jak rozwiązać problem z całą przestrzenią nazw. Po prostu szukam wygodnego sposobu odserializowania pojedynczego węzła z dokumentu XML, ale wydaje się to wiązać z koniecznością ręcznego rejestrowania/zarządzania obszarami nazw oraz przekazania ich z poziomu XmlReader do XmlSerializer.

Czy ktoś może zademonstrować sposób deserializacji pojedynczego węzła z dokumentu XML odczytanego za pomocą XmlReader, albo wskazując błąd w moim kodzie, albo pokazując alternatywne podejście?

+3

Poszukaj przykładu na 'XmlNamespaceManager'. Oto [jeden] (http://stackoverflow.com/a/14462578/815938), aby rozpocząć. – kennyzx

+0

@kennyzx: Przyjrzałem się 'XmlNamespaceManager' i' XmlNameTable' oraz 'XmlParserContext', a czego nie. Po prostu nie mam pojęcia, jak to ma pasować do mojego scenariusza. Czy mógłbyś zademonstrować mi to wykorzystanie? – stakx

Odpowiedz

5

następujące utwory:

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

Note przestrzeń nazw na wejściu: <ex:ElementOfInterest>.

+0

Czy możesz wyjaśnić, dlaczego zmieniłeś dokument wejściowy (tj. Dodał prefiks przestrzeni nazw do elementu)? Czy to sprawia, że ​​twój kod działa, czy też * moja * wersja przykładowego wejścia nie była w jakiś sposób poprawnie sformułowana/nieważna? – stakx

+1

Obie, rodzaj.Cóż, twój dokument wejściowy stwierdza, że ​​wynikowy obiekt powinien znajdować się w przestrzeni nazw 'urn: stakx: example'. Twoja klasa docelowa "ElementOfInterest' nie odzwierciedla tego, więc dodanie atrybutu klasy" XmlRoot (Namespace = ...) "było pierwszą zmianą. Teraz, gdy ponownie * przekształcisz * obiekt 'ElementOfInterest', wynikowy element XML będzie również w przestrzeni nazw' urn: stakx: example'. Aby dokonać deserializacji i serializacji symetryczne, musiałem umieścić element w tym obszarze nazw w danych wejściowych. – Tomalak

Powiązane problemy