2

我有一个 30MB 的大 XML 文件,想在其中找到几个元素。

该文件是一个有效的 pom.xml,我想从中获取所有依赖项(名称、组、版本)、子模块和父模块。您可以使用查看这样的文件

mvn help:effective-pom -Doutput=test.xml

对于我的 26MB 文件,scala 的 XML.load* 导致 java.lang.OutOfMemoryError: Java heap space

除了增加堆空间我还能做什么?

TIA,混蛋。

4

3 回答 3

6

您可以使用拉式解析,其中 XML 元素被视为一系列事件(打开标签a、打开标签i、文本、关闭标签i,...)。

这避免了将整个文件存储在内存中。

我已经在数百 MB 的 XML 文件上使用了它,没有任何重大问题。(当然,正如 Rex 在评论中指出的那样,如果您要恢复的元素本身很大,则没有明显的解决方法。)

拉解析器不如“常规”解析器(或Anti-XML)方便,因为它没有给您一棵树。相反,您必须管理状态以跟踪您在文档中的位置。

这是一个自包含的示例,展示了如何在 Scala 的 Wikipedia 页面上提取所有内部链接:

import scala.xml.Text
import scala.xml.pull._
import scala.io.Source

val src = Source.fromURL("http://en.wikipedia.org/wiki/Scala_(programming_language)")

val reader = new XMLEventReader(src)

val Internal = """/wiki/([\w_]*)""".r

var inLink = false
var linksTo = ""

for(event <- reader) { 
  event match { 
    case EvElemStart(_, "a", meta, _) => meta("href") match { 
      case Text(Internal(href)) =>
        linksTo = href
        inLink = true
      case _ => 
    } 
    case EvText(txt) if inLink => println(txt + " --> " + linksTo)
    case EvElemEnd(_, "a") => inLink = false
    case _ => ; 
  } 
}
于 2012-05-25T15:25:40.663 回答
4

简单地说,Scala 的标准库的 xml 并没有削减它。您可以使用拉解析器,但它几乎不实用。相反,我会使用Scales(认为 Anti-XML 也不是一种改进——我认为它们具有基于迭代的选择器,但我找不到它们)。

于 2012-05-25T18:07:33.770 回答
0

为了补充丹尼尔斯的观点,我当然有偏见,Scales Xml 提供了更高级别的拉解析所需的东西。有时,完整的树解析根本不是一个很好的匹配,并且传统上拉解析会迫使开发人员进行过多的管理。Scales 旨在通过迭代和路径的概念使这更简单。

如果您可以确定所需的路径,那么 Scales 将为每个项目拉出迷你树。这通过组合 iteratee 的结果(每个路径一个 iteratee)并允许用户折叠每次出现的结果来工作。

这在恒定空间中运行,仅受您在解析期间保留的对象的限制,但比基于树的解析要慢。(Scales 需要大约 200-220MB 的堆来处理 30MB 的树 - 但如果文档易于优化,可以减少到 170-180 - 请参阅内存优化 了解更多详细信息)

有关示例,请参阅Pull Parsing 文档

于 2012-06-23T10:38:03.890 回答