Scala在大(30MB)xml文件中查找元素

时间:2012-05-25 14:43:15

标签: xml scala maven

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

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

查看此类文件
mvn help:effective-pom -Doutput=test.xml

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

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

TIA,bastl。

3 个答案:

答案 0 :(得分:6)

您可以使用pull parsing,其中XML元素被视为一系列事件(开放标记a,开放标记i,文本,关闭标记i ,. ..)。

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

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

拉解析器不如“常规”(或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 _ => ; 
  } 
}

答案 1 :(得分:4)

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

答案 2 :(得分:0)

要添加Daniels点,我当然有偏见,Scales Xml提供了更高级别的pull解析所需的内容。有时,完全成熟的树解析并不是一个很好的匹配,拉解析传统上会对开发人员施加过多的管理。 Scales旨在通过迭代和路径概念使这更简单。

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

它在常量空间中运行,仅受在解析期间保留的对象的限制,但比基于树的解析慢。 (Scales需要大约200-220MB的堆来处理30MB树 - 但如果文档易于优化,则可以减少到170-180 - 有关详细信息,请参阅memory optimisation

请参阅the Pull Parsing docs for examples