如何在.NET中处理非常大的XML文件时最好地使用XPath?

17

我需要在C#中处理相当大的XML文件(这里的大可能会达到1GB),包括执行一些复杂的XPath查询。我的问题是,我通常通过System.XML库进行处理的标准方式喜欢在对其进行任何操作之前将整个文件加载到内存中,这可能会导致这些大小的文件出现内存问题。

我不需要更新这些文件,只需读取它们并查询其中包含的数据。一些XPath查询非常复杂,涉及多个父子级关系层次-我不确定是否会影响使用流读取器而不是将数据作为块加载到内存中的能力。

我可以看到使其工作的一种方法是使用基于流的方法执行简单的分析,也许将XPath语句包装到我稍后可以运行在文件上的XSLT转换中,尽管这似乎有点复杂。

或者,我知道有一些元素XPath查询无法遍历,因此我猜我可以根据原始树结构将文档分解成一系列较小的片段,这些片段可能足够小以在不引起太多混乱的情况下在内存中处理。

我已经试图解释了我的目标,所以如果我的总体方法完全错误,我相信你们可以纠正我...

10个回答

10
XPathReader是解决方案。它不是C#运行时的一部分,但可从Microsoft下载。以下是MSDN文章链接。
如果您使用XmlTextReader构建XPathReader,您将获得流读取的效率和XPath表达式的便利性。
我尚未在千兆字节大小的文件上使用它,但我已经在数十兆字节的文件上使用过它,这通常足以减慢基于DOM的解决方案。
以下是引用:“XPathReader提供了以流形式执行XML文档上XPath的功能”。 从Microsoft下载

1
XPathReader的状态/版本不确定。自2004年以来似乎没有更新。请参见https://dev59.com/FnRB5IYBdhLWcg3w7riV - mjv

2

2
吉盘 XML 文件!我不羡慕你这个任务。
有没有更好的方式发送文件?例如,如果它们正在通过网络发送给您,则更高效的格式可能对所有相关方都更好。将文件读入数据库并不是一个坏主意,但可能非常耗时。
除非您拥有 64 位操作系统和大量内存,否则不要尝试通过读取整个文件来在内存中完成所有操作。如果文件变成 2、3、4GB 呢?
另一种方法是读取 XML 文件并使用 SAX 解析文件,并根据某些逻辑分割编写较小的 XML 文件。然后,您可以使用 XPath 处理这些文件。我曾经在 20-30MB 的文件上使用过 XPath,速度非常快。我最初打算使用 SAX,但想尝试一下 XPath,结果惊讶地发现它非常快。我节省了很多开发时间,每次查询可能只损失了 250ms。我用 Java 进行解析,但我认为 .NET 中可能没有太大的区别。
我读到 XML::Twig(Perl CPAN 模块)是专门编写用于处理基于 SAX 的 XPath 解析的。您能使用其他语言吗?
这可能也会有所帮助:https://web.archive.org/web/1/http://articles.techrepublic%2ecom%2ecom/5100-10878_11-1044772.html

1
为了使用标准的.NET类执行XPath查询,整个文档树需要加载到内存中,如果需要占用高达1GB的空间,则可能不是一个好主意。在我看来,XmlReader是处理这种任务的一个很好的类。

XPathDocument 也是一个轻量级的类。 - Dirk Vollmar
2
XPathDocument 的问题在于整个文档将被加载到内存中。 - Darin Dimitrov

1

看来您已经尝试使用XPathDocument,并且无法在内存中容纳解析的XML文档。

如果是这种情况,在开始拆分文件(最终是正确的决定!)之前,您可以尝试使用Saxon XSLT/XQuery处理器。它具有已加载的XML文档的非常高效的内存表示形式("tinytree"模型)。此外,Saxon SA(需要付费的schema-aware版本)具有一些流扩展。在这里了解更多信息。


1

把整个东西读入数据库,然后使用临时数据库进行操作怎么样?这可能更好,因为您的查询可以使用TSQL更有效地完成。


另一个选择是创建一个带有数据类的通用列表。用xml数据填充它,然后使用linq查询它。我最近一直在这样做,效果非常好。 - Donny V.

1

我认为最好的解决方案是制作自己的XML解析器,可以读取小块而不是整个文件,或者您可以将大文件拆分成小文件,并使用这些文件与dotnet类一起使用。

问题在于,在整个数据可用之前,您无法解析某些数据,因此我建议使用自己的解析器而不是dotnet类。


0

鉴于您的数据大小可能达到GB级别,您是否考虑使用ADO.NET与XML作为数据库。此外,内存占用也不会很大。

另一种方法是使用Linq to XML,并使用像XElementStream这样的元素。希望这可以帮助到您。


0
你尝试过XPathDocument吗? 这个类被优化为高效处理XPath查询。
如果你无法使用XPathDocument有效地处理输入文件,可以考虑使用XmlReader进行预处理和/或拆分输入文件。

0

你已经概述了你的选择。

要么你需要放弃XPath并使用XmlTextReader,要么你需要将文档分成可管理的块,然后在这些块上使用XPath。

如果你选择后者,请使用XPathDocument,它的只读限制可以更好地利用内存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接