2015-01-27 6 views
6

단일 패스에서 큰 XML 문서 (XmlReader 사용)를 처리하려고하고 있습니다. XmlSerializer을 사용하는 특정 요소.큰 XML 문서에서 단일 요소의 비 직렬화 : 네임 스페이스 문제로 인해 xmlSerializer.Deserialize (xmlReader.ReadSubtree())가 실패합니다.

다음은이 작업을 수행 한 방법을 보여주는 몇 가지 코드 및 작은 모의 XML 문서입니다. XmlReader를 사용하는

이론적 근거 : 나는 이런 이유로 나는 메모리로로드하지 않으려는 매우 큰 XML 문서 (10 – 250메가바이트), 처리하고1.. 따라서 XmlDocument은 문제가되지 않습니다. 2. 특정 요소 만 추출하고 싶습니다. 일반적으로 저는 다른 대부분의 콘텐츠를 무시할 수 있습니다. XmlReader은 관련성없는 콘텐츠를 건너 뛰는 효율적인 수단을 제공합니다. 3. 내가 처리 할 수있는 모든 요소가 있는지 여부를 미리 알지 못합니다. 따라서 Xpath/XQuery 또는 LINQ to XML 기반 쿼리를 사용하지 않고 있습니다. 크기 때문에 XML 파일을 한 번 통과시키기를 원하기 때문입니다.

InvalidOperationException :

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

코드의 마지막 행은 다음 내부 예외 발생. "네임 스페이스 접두어 ex가 정의되어 있지 않습니다" 분명히

XmlSerializerxsi:type 속성의 값 내부의 ex 네임 스페이스 접두사를 인식하지 못합니다.

이것은 내가 가지고있는 한 가지 오류 일 뿐이지 만 더 큰 문제는 전체 네임 스페이스 문제를 해결하는 방법을 모르는 것입니다. XML 문서에서 단 하나의 노드를 역 직렬화하는 편리한 방법을 찾고 있지만 이름 공간을 수동으로 등록/관리해야하고, XmlReader에서 XmlSerializer으로 전달해야합니다.

XmlReader으로 읽은 XML 문서에서 단일 노드를 역 직렬화하는 방법을 코드에서 오류를 지적하거나 다른 방법으로 보여줄 수 있습니까?

+3

'XmlNamespaceManager'에서 예제를 찾으십시오. 여기에 [one] (http://stackoverflow.com/a/14462578/815938)이 시작되었습니다. – kennyzx

+0

@kennyzx :'XmlNamespaceManager','XmlNameTable','XmlParserContext'를 살펴 보았습니다. 나는 그것이 어떻게 내 시나리오에 함께 맞추어 져야하는지 전혀 모른다. 그 용도를 설명해 주시겠습니까? – stakx

답변

5

다음 작품 :

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

주 입력에서 네임 스페이스 : <ex:ElementOfInterest>.

+0

입력 문서를 변경 한 이유 (즉, 요소에 네임 스페이스 접두어를 추가 한 이유)를 설명 할 수 있습니까? 코드를 작동시키는 것입니까? 예제 입력의 * my * 버전이 어떤 식 으로든 형식이 잘못되었거나 유효하지 않았기 때문입니까? – stakx

+1

둘 다, 일종의.음, 입력 문서는 결과 객체가'urn : stakx : example' 네임 스페이스에 있어야한다고 말합니다. 귀하의 목표 클래스'ElementOfInterest'는 그것을 반영하지 않았으므로,'XmlRoot (Namespace = ...)'클래스 속성을 추가하는 것이 첫 번째 변경 사항이었습니다. 이제'ElementOfInterest' 객체를 다시 직렬화하면 결과 XML 요소도'urn : stakx : example' 네임 스페이스에있게됩니다. deserialization과 serialization을 대칭으로 만들기 위해 요소를 입력의 네임 스페이스에 넣어야했습니다. – Tomalak