我在 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 处理和流式 处理。
DOM 处理读取整个源文档,然后允许程序员对内存表示 执行操作。从程序员的角度来看,这通常是处理 XML 文档的最简单方法,但是所使用的内存与 XML 文档的大小成正比。这意味着处理大型文档会占用大量内存。
流式处理 处理读取 XML 文档并在读取时动态处理文档。从程序员的角度来看,这使得文档更难使用,因为他不能同时访问整个文档,只能访问一小部分。它具有持续使用内存的优点。也就是说,您不需要在内存中保存整个文档,只需保存您正在操作的部分。
鉴于您的内存限制,您几乎肯定必须使用流式处理方法。使用流式方法,您可以读取文件,提取您感兴趣的部分,然后继续,从而不会为您不感兴趣的文档部分积累额外的内存。
请注意,如果您从文件中提取大量 信息并将其保存在内存中,您将有效地抵消流式处理的好处,因为您只是将所有数据保存在无论如何内存。如果您发现自己处于这种情况并且遇到内存问题,请考虑在读入数据后将数据流式传输到文件中,而不是将其保存在内存中。您可以将流式传输视为对 XML 的转换。您阅读整个文档一次,转换(保留/更改/丢弃)您感兴趣的部分,并在转换完成后立即将它们写出来。
scala.xml现在,scala.xml 包使用 DOM 样式方法来处理 XML,因此它可能不适合您。您的两个解决方案都建立在这个包之上。我建议与具有 XML 流支持的 Java 库交互(我不知道有任何 Scala 库支持)。
javax.xmlJava 标准库已经有各种工具以流方式处理 XML。我个人只将这些工具用于基于流的 编写 XML 文件,但它们应该非常简单,并且非常适合任何场景。
Jackson( https://github.com/FasterXML/jackson-core ) 支持基于流的 XML 处理,这可能比 javax.xml 中的 API 功能更丰富。确保您使用他们的流式 API,因为他们也有基于 DOM 的 API,这将再次给您留下内存问题。
关于XML 解析性能 Scala,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28035092/
我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我正在使用ruby1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
简而言之错误:NOTE:Gem::SourceIndex#add_specisdeprecated,useSpecification.add_spec.Itwillberemovedonorafter2011-11-01.Gem::SourceIndex#add_speccalledfrom/opt/local/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91./opt/local/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/rails/gem_dependency.rb:275:in`==':und
我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和
我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("
我想用Nokogiri解析HTML页面。页面的一部分有一个表,它没有使用任何特定的ID。是否可以提取如下内容:Today,3,455,34Today,1,1300,3664Today,10,100000,3444,Yesterday,3454,5656,3Yesterday,3545,1000,10Yesterday,3411,36223,15来自这个HTML:TodayYesterdayQntySizeLengthLengthSizeQnty345534345456563113003664354510001010100000344434113622315
我正在使用Ruby解决一些ProjectEuler问题,特别是这里我要讨论的问题25(Fibonacci数列中包含1000位数字的第一项的索引是多少?)。起初,我使用的是Ruby2.2.3,我将问题编码为:number=3a=1b=2whileb.to_s.length但后来我发现2.4.2版本有一个名为digits的方法,这正是我需要的。我转换为代码:whileb.digits.length当我比较这两种方法时,digits慢得多。时间./025/problem025.rb0.13s用户0.02s系统80%cpu0.190总计./025/problem025.rb2.19s用户0.0
我使用的第一个解析器生成器是Parse::RecDescent,它的指南/教程很棒,但它最有用的功能是它的调试工具,特别是tracing功能(通过将$RD_TRACE设置为1来激活)。我正在寻找可以帮助您调试其规则的解析器生成器。问题是,它必须用python或ruby编写,并且具有详细模式/跟踪模式或非常有用的调试技术。有人知道这样的解析器生成器吗?编辑:当我说调试时,我并不是指调试python或ruby。我指的是调试解析器生成器,查看它在每一步都在做什么,查看它正在读取的每个字符,它试图匹配的规则。希望你明白这一点。赏金编辑:要赢得赏金,请展示一个解析器生成器框架,并说明它的