1

如果我有一个像下面这样的大 xml 文件。在 Java 或 Scala 中解析它的最快方法是什么。流式传输单个元素很重要,但不是绝对必要的

我感兴趣的是从每个结果对象中获取属性值。

<Response>
    <Result att1="1", att2="2", att3="3", att4="4", att5="5"/>
    <Result att1="1", att2="2", att3="3", att4="4", att5="5"/>
    <Result att1="1", att2="2", att3="3", att4="4", att5="5"/>
    <Result att1="1", att2="2", att3="3", att4="4", att5="5"/>
</Response>
4

2 回答 2

7

如果您的文件很大并且您不想将整个内容加载到内存中(即 DOM),那么您可以采用的一种路径是拉解析路径。如果您想在 scala 中进行拉解析,寻找“开始元素”事件以检查属性,那么您可以执行以下操作:

import scala.io.Source
import java.io.File
import scala.xml.pull.XMLEventReader
import scala.xml.pull.EvElemStart

val src = Source.fromFile(new File(pathToXml))
val reader = new XMLEventReader(src)
reader foreach{ 
  case EvElemStart(_, _, attrs, _) =>
    //do something here

  case _ =>
}

遵循这种方法应该确保您的文件不会被读入内存并且应该很快。

于 2013-08-12T16:29:04.240 回答
2

Scala XML(可能很慢且需要内存)

cmbaxter 的答案在技术上是正确的,但可以使用“flatMap that shit”模式进行改进:-)

    import io.Source
    import xml.pull._

    // Make it "def", because the Source is stateful and may be exhausted after it is read
    def xmlsrc=Source.fromString("""<Response>
         |     <Result att1="1" att2="2" att3="3" att4="4" att5="5"/>
         |     <Result att1="1" att2="2" att3="3" att4="4" att5="5"/>
         |     <Result att1="1" att2="2" att3="3" att4="4" att5="5"/>
         |     <Result att1="1" att2="2" att3="3" att4="4" att5="5"/>
         | </Response>""")

    // Also as "def", because the result is an iterator that may be exhausted
    def xmlEr=new XMLEventReader(xmlsrc)

    // flatMap keeps the "outer shape" of the type it operates, so we are still dealing with an iterator

    def attrs = xmlEr.flatMap{
         |   case e : EvElemStart => e.attrs.map(a => (a.key, a.value))
         |   case _ => Iterable.empty
         | }

    // Now lets look what is inside:
    attrs.foreach(println _)

    // Or just let's collect all values from "att5"
    attrs.collect{ case (name, value) if name == "att5" =>value}.foreach(println _)

缩放 XML(更快,需要更少的内存)

但这不会是最快的方式。与其他解决方案(如基准测试所示)相比,Scala API 非常慢且占用大量内存。但幸运的是,有一个更快、更少内存消耗的解决方案:

    import scales.utils._
    import ScalesUtils._
    import scales.xml._
    import ScalesXml._
    import java.io.StringReader

    def xmlsrc=new StringReader("""<Response>
         |     <Result att1="1" att2="2" att3="3" att4="4" att5="5"/>
         |     <Result att1="1" att2="2" att3="3" att4="4" att5="5"/>
         |     <Result att1="1" att2="2" att3="3" att4="4" att5="5"/>
         |     <Result att1="1" att2="2" att3="3" att4="4" att5="5"/>
         | </Response>""")
    def pull=pullXml(xmlsrc)
    def attributes = pull flatMap {
         |   case Left(elem : Elem) => elem.attributes
         |   case _ => Nil
         | } map (attr => (attr.name, attr.value))

    attributes.foreach(println _)

完成后不要忘记关闭迭代器。在这里没有必要,因为我正在使用StringReader.

反 XML

还有Anti XML库,它在基准测试中看起来相当不错,而且似乎有一个非常不错的 API。不幸的是,我无法让它与 Scala 2.10 一起运行,因此我无法提供运行示例。

结论

通过上面的示例,您应该能够编写一个小型测试应用程序。有了这些,您可以运行自己的基准测试。查看上面引用的基准,我想 Scales XML 可能会解决您的问题。但如果没有真正的测量,这真的只是一个猜测。

对自己进行基准测试,也许您可​​以发布您的结果。

于 2013-08-13T10:45:09.177 回答