使用 xmlReader 在 C# 中过滤特定元素值的大 XML

Filter Large XML for specific element value in C# Using xmlReader

在此主题中:

我能够使用 XDocument 筛选 xml 个文件以查找特定元素。然而,对于巨大的 xml 文件,XDocument 似乎不是一个可行的解决方案,因为它失败并显示 System.OutOfMemoryException 消息。四处挖掘,看起来 xmlReader 在处理大 xmls.

时内存效率更高

如何重写已接受的答案,以使用 xmlReader 以获得相同的结果?

我使用这样的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XmlReader reader = XmlReader.Create(FILENAME);

            while (!reader.EOF)
            {
                if (reader.Name != "Entry")
                {
                    reader.ReadToFollowing("Entry");
                }
                if (!reader.EOF)
                {
                    XElement entry = (XElement)XElement.ReadFrom(reader);
                }
            }

        }
    }
}

请尝试以下解决方案。

它的可扩展性很强,可以毫无问题地处理多 GB 大小的 XML 文件。

XStreamingElement 正在使用一种扩展方法,该方法流式传输由 <section>Section 1</section> 节点使用 XmlReader 过滤的源 XML。

c#

void Main()
{
    const string inputXMLFile = @"e:\Temp\Sanosi.xml";
    const string outputXMLFile = @"e:\Temp\Sanosi_Streamed.xml";
    const string ROW = "Entry";
    const string FILTER = "Section 1";

    // Stream XML to file system
    System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
    timer.Start();

    // Shape output XML
    XStreamingElement newXML = new XStreamingElement("root",
       from element in StreamElements(inputXMLFile, ROW)
            .Where(x => x.Element("section").Value.Equals(FILTER))
       select new XElement(ROW, element.Elements("image")
          ));

    newXML.Save(outputXMLFile, SaveOptions.OmitDuplicateNamespaces);

    FileInfo fileBefore = new FileInfo(inputXMLFile);
    FileInfo fileAfter = new FileInfo(outputXMLFile);

    timer.Stop();

    Console.WriteLine("Streamed XML file '{0}', {1} bytes to file system as: '{2}', {3} bytes{5}Elapsed time: {4}",
      fileBefore.FullName
      , fileBefore.Length
      , fileAfter.FullName
      , fileAfter.Length
      , timer.Elapsed
      , Environment.NewLine);
}

private static IEnumerable<XElement> StreamElements(string fileName, string elementName)
{
    using (var rdr = XmlReader.Create(fileName))
    {
        rdr.MoveToContent();
        while (rdr.Read())
        {
            if ((rdr.NodeType == XmlNodeType.Element) && (rdr.Name == elementName))
            {
                var e = XElement.ReadFrom(rdr) as XElement;
                yield return e;
            }
        }
        rdr.Close();
    }
}