2016-09-11 2 views
1

ノードの一部を除いて大きなxmlを書き直したいと思います。 system.xml.xmlreaderを使用して、XMLファイル(100 MBのMBを読み込み、メモリにすべて読み込めません)を1行ずつ読み込もうとしています。その一部を読み込み、 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 /どのように、読み--XMLファイルごとの使用-のXMLReader・イン・C-シャープになりました更新 – 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

回答、あなたのコードは完璧に動作 –

+0

貴重な提案を@JLRisheにもう一度感謝。まさに私が必要としていたものであり、私はそれに感謝します。シーケンスについての質問ですが、シーケンスが正しく注文されない可能性がありますか? 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

関連する問題