使用 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();
}
}
在此主题中:
我能够使用 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();
}
}