2016-09-11 2 views
1

일부 노드가없는 큰 xml을 다시 작성하고 싶습니다. system.xml.xmlreader를 사용하여 한 줄씩 XML 파일 (100s의 MB를 읽을 수없고 메모리에 모두 읽을 수 없음)을 읽으려고합니다. 일부를 읽는 방법을 찾기 위해 고심하고 xDocument를 분리하고 해당 xDocument를 디스크에 저장하십시오.대용량 XML 파일 다시 작성 - 특정 노드 제외

내가 뭘 생각하고 봤는데 뭔가 같은 :

 using (XmlReader reader = XmlReader.Create(_xml_path)) 
     { 
      using (XmlWriter writer = XmlWriter.Create(@"filteredxml.xml")) 
      { 
       reader.MoveToContent(); 

       while (reader.Read()) 
       { 
        if (reader.NodeType == XmlNodeType.Element) 
        { 
         if (reader.Name != "EL_TO_BE_REMOVED") 
         { 
          //writer.WriteNode(reader.ReadOuterXml()); 

         } 
        } 
       } 
      } 
     } 

하지만 reader.ReadOuterXml()는 단순히 첫 번째 요소로 이동하고 제가 원하는 요소를 필터링 말도없이, 파일에 모든 자손을 기록 무시한다.

+0

은 다음 포스팅에서 내 대답을 참조하십시오 http://stackoverflow.com/questions/34274568/how-to-read-an-xml-file-by-using-xmlreader-in-c-sharp – jdweng

답변

0

큰 파일과 메모리 제약이있는 경우 DOM 대신 SAX로 구문 분석해야합니다. XMLReader는 실제로 C#과 동일합니다.

입력에 대한 XMLReader, 출력용 XMLWriter 및 RemoveMe라는 노드 (모든 내용 포함)를 제거하는 카운터가 기본 접근 방식 일 수 있습니다.

관련 요소별로 속성을 복제하는 내부 루프에 주목하십시오.

 using (XmlReader reader = XmlReader.Create(OriginalXml)) 
     { 
      XmlWriterSettings ws = new XmlWriterSettings(); 
      ws.Indent = true; 
      using (XmlWriter writer = XmlWriter.Create(FilteredXml, ws)) 
      { 
       int skip = 0; 
       while (reader.Read()) 
       { 
        switch (reader.NodeType) 
        { 
         case XmlNodeType.Element: 
          skip += reader.Name.Equals(RemoveMe) ? 1 : 0; 
          if (skip == 0) 
          { 
           writer.WriteStartElement(reader.Name); 
           while (reader.MoveToNextAttribute()) 
            writer.WriteAttributeString(reader.Name, reader.Value); 
          } 

          break; 
         case XmlNodeType.Text: 
          if (skip == 0) 
          { 
           writer.WriteString(reader.Value); 
          } 
          break; 
         case XmlNodeType.XmlDeclaration: 
         case XmlNodeType.ProcessingInstruction: 
          if (skip == 0) 
          { 
           writer.WriteProcessingInstruction(reader.Name, reader.Value); 
          } 
          break; 
         case XmlNodeType.Comment: 
          if (skip == 0) 
          { 
           writer.WriteComment(reader.Value); 
          } 
          break; 
         case XmlNodeType.EndElement: 
          if (skip == 0) 
          { 
           writer.WriteFullEndElement(); 
          } 
          skip -= reader.Name.Equals(RemoveMe) ? 1 : 0; 
          if (skip < 0) 
          { 
           throw new Exception("wrong sequence"); 
          } 
          break; 
        } 
       } 

      } 
     } 
+1

답변이 지금 바뀌 었습니다. 귀한 제안을 위해 @JLRishe에게 다시 감사합니다. –

+0

코드가 완벽하게 작동합니다. 정확히 내가 필요로하는 것이고 나는 그것에 대해 감사드립니다. 시퀀스에 대한 질문이지만 순서가 올바르게 정렬되지 않을 가능성이 있습니까? XML 이외의 손상? – ponyboil

+0

나는 또한 그렇게 생각한다 : 오직 손상된 XML 만. 보내 주신 의견에 다시 한 번 감사드립니다. –

0

이것은 XSLT의 직업처럼 들립니다.

XSL 변환 (RemoveElement.xslt) :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="@* | node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="EL_TO_BE_REMOVED" /> 

</xsl:stylesheet> 

C# 코드 실행이 변환 :

var transform = new XslCompiledTransform(); 
transform.Load("xslt/path/RemoveElement.xslt"); 

transform.Transform("input/xml/path/inputFile.xml", "output/xml/path/outputFile.xml"); 
+0

@ MachineLearning XSLT가 자주 실행되는 방식과 XSLT 사양 (AFAIK)에 기반을 두지 않는 방법에 대한 일반적인 개요라고 생각합니다. .NET의 XSLT 프로세서가 어떻게 구현되는지는 모르겠지만 입력 및 출력 스트림에서 작동하도록 설계되었으므로 상당히 현명한 방법으로 구현 될 수 있습니다. 그럴만 한 가치가있어. – JLRishe