SAX解析器在Java中能否使用XPath?

8

我正在尝试迁移一个使用DOM解析和许多XPath表达式的类到SAX解析。对于我来说,DOM解析很好,但我尝试解析的一些文件太大了,它们会导致服务器超时。我想重用XPathSAX解析,但我不确定是否可能,如果不可能,你能帮我吗?因为当我仅使用SAX时,我不知道以下代码将是什么样子:

Document doc = bpsXml.getDocument();
String supplierName = BPSXMLUtils.getXpathString(doc, "/Invoice/InvoiceHeader/Party[@stdValue='SU']/Name/Name1");
String language = BPSXMLUtils.getXpathString(doc, "/Invoice/InvoiceHeader/InvoiceLanguage/@stdValue");

等等,你为什么要从使用XPath的DOM转换到SAX?如果是因为你从网络获取文件而服务器花费太长时间来发送文件,那么改变获取文件的方式,而不是改变解析文件的方式。 - cdeszaq
还有这个相关的SO帖子。其中几个答案提到了可以用于此的工具和API。 - jogojapan
3个回答

6
仅使用SAX解析器不会在内存中构建XML树的表示形式(这就是为什么SAX更具内存效率)。每当遇到新的XML元素时,它只会触发“事件”。您必须将上下文(通常是父元素的堆栈)保存在内存中以“知道”您在树中的位置。
由于您没有树形结构的内存,因此无法使用XPath。您只能测试当前的“上下文”(手动管理的堆栈)来查询文档。请记住,SAX解析器只对文件进行一次运行,因此文件中的顺序很重要。
幸运的是,还有其他方法,如VTD-XML,它是一个库,用于在内存中构建XML树,但仅用于结构部分,它不会从文件中提取实际内容,内容是按需提取的。它比DOM解析器节省更多的内存,同时仍允许XPath。我个人在工作中使用这个库来解析大约700MB的XML文件,并使用XPath(是的,这很疯狂,但它可以工作,并且非常快)。

这是一个非常好的想法,但当你有由许多短数据的XML元素组成的大文件(2GB以上)时,它的效果并不那么好。在实践中,你可以减少50/60%所需的内存,这很棒,但当你有非常大的文件时还不够。而现在的数据增长速度越来越快... - OGrandeDiEnne
经过这么多年,我使用VTD-XML解析了2GB以上的文件。它表现非常出色,内存根本不是问题。你尝试过它并有不好的经历吗?你能分享更多信息吗? - Vincent Robert
你给解析程序分配了多少内存(-Xmx)? - OGrandeDiEnne
我的大部分解析工作都是使用默认的Xmx(64 MB)完成的,但有时为了安全起见,我不得不将它推高到1GB(从记忆中得知,我不再从事这些话题)。 - Vincent Robert

3
IMHO,处理XML最简单的方法是使用StAX,即XML流API。它结合了DOM和SAX的优点(并为您提供更轻松的迁移)。您仍然有一个指向XML元素的光标(就像在SAX中),但是您的代码将光标向前移动。这使得XML处理代码变得更加易读。它还解决了内存问题,因为只需要保存当前XML元素。这里也有一个不错的tutorial
另外回答您的原始问题:在Google上短暂搜索后,我发现没有易于接受的方法,这可能意味着所有自定义解决方案都不稳健,未得到维护和充分测试。

1

转换为SAX解析(或StAX)将需要完全改变您的方法。 看起来您没有充分意识到需要多少工作。 为了使任何建议有意义,我们需要知道文件的大小以及您想对数据进行什么样的处理。 例如,如果您正在筛选数据,则使用文档投影的XQuery实现可能是一个很好的答案(这将在幕后自动使用SAX构建仅包含您真正感兴趣的数据子集的树形结构)。


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