2016-09-11 5 views
1

Я хотел бы переписать большой xml без некоторых его узлов. Я пытаюсь прочитать XML-файл (100 мс MB, не могу прочитать все это в памяти) по строкам, используя system.xml.xmlreader - изо всех сил пытаюсь найти способ прочитать его части, записать их на отдельный 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-a-xml-file-by-use-xmlreader-in-c-sharp – jdweng

ответ

0

В случае больших ограничений файлов и памяти вы должны анализировать SAX вместо DOM: 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 Transform (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). Я не знаю, как реализован XSLT-процессор .NET, но поскольку он предназначен для работы с потоками ввода и вывода, он может сделать это довольно разумно. Стоит попробовать, по крайней мере. – JLRishe