XML 解析性能 Scala
XML Parsing Performance Scala
我在 Scala 中使用 XML,在 内存有限 的系统中解析可以达到 ~20MB 的文件] 资源。我必须读取整个文件,并且必须从中提取所有数据。更具体地说,我必须读取的节点具有有限的属性和值。
我想知道在性能方面最好的方法是什么(或者两者是否具有相同的性能)。我问这个是因为我不知道 Scala 如何处理它的 XML 库,我可能会遗漏一些细节。
第一种方法
def firstApproach(root: Elem) =
for { n <- root \ "node" } yield handleNodeAttribute(n)
private def handleNodeAttribute(n: Node) = n match {
case node @ <node /> if (node \ "@attr").text == "type1" => // do something
// here other possible cases -> type2, type3
}
第二种方法
def secondApproach(root: Elem) = {
val nodes = root \ "node"
val type1 = filterNodesByAttribute(nodes, "attr", "type1")
// and so on -> type2, type3
}
private def filterNodesByAttribute(nodes: NodeSeq, attr: String, value: String) = {
nodes filter (node => (node \ ("@" + attr)) text == value)
}
那么,与使用模式匹配和每个问题迭代一次(for-yield 循环)相比,使用 XPath 方法处理所有文件有什么优势吗?
两种解决方案的性能相似,可能都不适合您的内存限制。
当我们谈论 XML 处理时,通常有两种方法,DOM 处理和 Streaming处理中。
DOM 处理中
DOM处理读取整个源文档,然后允许程序员对内存表示.从程序员的角度来看,这通常是处理 XML 文档的最简单方法,但是使用的内存与 XML 文档的大小成正比。这意味着处理大型文档需要 大量 内存。
流处理
Streaming 处理读取 XML 文档并在读取时即时处理文档。从程序员的角度来看,这使得文档更难使用,因为他不能同时访问整个文档,只能访问一小部分。它具有持续使用内存的优点。也就是说,您不需要整个文档在内存中,只需要您正在操作的部分。
鉴于您的内存限制,您几乎肯定必须使用流式处理方法。使用流式方法,您可以读取文件,提取您感兴趣的部分,然后继续,从而不会为您不感兴趣的文档部分积累额外的内存。
请注意,如果您从文件中提取 大量 的信息并将其保存在内存中,您将有效地抵消流式处理的好处,因为您将无论如何将所有数据保存在内存中。如果您发现自己处于这种情况并且遇到内存问题,请考虑在读入数据后将数据流式传输到文件中,而不是将其保存在内存中。您可以将流媒体视为对 XML 的转换。您通读了整个文档一次,转换 (keeping/changing/discarding) 您感兴趣的部分,并在转换完成后立即 将它们写出来。
scala.xml
现在,scala.xml
包使用 DOM 风格的方法来 XML 处理,因此它可能不适合您。您的两个解决方案都建立在这个包之上。我建议与 Java 库连接,该库支持 XML 的流式传输(我不知道有任何 Scala 支持)。
javax.xml
Java 标准库已经有各种工具以流方式处理 XML。我个人仅将这些工具用于 编写 的 XML 文件,但它们应该非常简单明了并且非常适合任何场景。
杰克逊
Jackson(https://github.com/FasterXML/jackson-core) 支持 XML 的基于流的处理,这可能比 javax.xml
中的 API 功能更丰富。确保您使用他们的流式 API,因为他们也有基于 DOM 的 API,这将再次给您带来内存问题。
我在 Scala 中使用 XML,在 内存有限 的系统中解析可以达到 ~20MB 的文件] 资源。我必须读取整个文件,并且必须从中提取所有数据。更具体地说,我必须读取的节点具有有限的属性和值。
我想知道在性能方面最好的方法是什么(或者两者是否具有相同的性能)。我问这个是因为我不知道 Scala 如何处理它的 XML 库,我可能会遗漏一些细节。
第一种方法
def firstApproach(root: Elem) =
for { n <- root \ "node" } yield handleNodeAttribute(n)
private def handleNodeAttribute(n: Node) = n match {
case node @ <node /> if (node \ "@attr").text == "type1" => // do something
// here other possible cases -> type2, type3
}
第二种方法
def secondApproach(root: Elem) = {
val nodes = root \ "node"
val type1 = filterNodesByAttribute(nodes, "attr", "type1")
// and so on -> type2, type3
}
private def filterNodesByAttribute(nodes: NodeSeq, attr: String, value: String) = {
nodes filter (node => (node \ ("@" + attr)) text == value)
}
那么,与使用模式匹配和每个问题迭代一次(for-yield 循环)相比,使用 XPath 方法处理所有文件有什么优势吗?
两种解决方案的性能相似,可能都不适合您的内存限制。
当我们谈论 XML 处理时,通常有两种方法,DOM 处理和 Streaming处理中。
DOM 处理中
DOM处理读取整个源文档,然后允许程序员对内存表示.从程序员的角度来看,这通常是处理 XML 文档的最简单方法,但是使用的内存与 XML 文档的大小成正比。这意味着处理大型文档需要 大量 内存。
流处理
Streaming 处理读取 XML 文档并在读取时即时处理文档。从程序员的角度来看,这使得文档更难使用,因为他不能同时访问整个文档,只能访问一小部分。它具有持续使用内存的优点。也就是说,您不需要整个文档在内存中,只需要您正在操作的部分。
鉴于您的内存限制,您几乎肯定必须使用流式处理方法。使用流式方法,您可以读取文件,提取您感兴趣的部分,然后继续,从而不会为您不感兴趣的文档部分积累额外的内存。
请注意,如果您从文件中提取 大量 的信息并将其保存在内存中,您将有效地抵消流式处理的好处,因为您将无论如何将所有数据保存在内存中。如果您发现自己处于这种情况并且遇到内存问题,请考虑在读入数据后将数据流式传输到文件中,而不是将其保存在内存中。您可以将流媒体视为对 XML 的转换。您通读了整个文档一次,转换 (keeping/changing/discarding) 您感兴趣的部分,并在转换完成后立即 将它们写出来。
scala.xml
现在,scala.xml
包使用 DOM 风格的方法来 XML 处理,因此它可能不适合您。您的两个解决方案都建立在这个包之上。我建议与 Java 库连接,该库支持 XML 的流式传输(我不知道有任何 Scala 支持)。
javax.xml
Java 标准库已经有各种工具以流方式处理 XML。我个人仅将这些工具用于 编写 的 XML 文件,但它们应该非常简单明了并且非常适合任何场景。
杰克逊
Jackson(https://github.com/FasterXML/jackson-core) 支持 XML 的基于流的处理,这可能比 javax.xml
中的 API 功能更丰富。确保您使用他们的流式 API,因为他们也有基于 DOM 的 API,这将再次给您带来内存问题。