我通常使用Nokogiri作为我的XML解析器。
我有以下XML:
<albums>
<aldo_nova album="aldo nova">
<release_date value="19820401"/>
</aldo_nova>
<classix_nouveaux album="Night People"/>
<release_date value="19820501"/>
</classix_nouveaux>
<engligh_beat album="I Just Can't Stop It"/>
<release_date value="19800501"/>
</engligh_beat>
</albums>
我想获得1980年1月1日至1982年4月15日期间发布的所有专辑:
<aldo_nova album="aldo nova">
<release_date value="19820401"/>
</aldo_nova>
<engligh_beat album="I Just Can't Stop It"/>
<release_date value="19800501"/>
</engligh_beat>
如何按release_date
范围过滤/查询XML?
答案 0 :(得分:0)
您的XML格式错误。在解析之后,这就是Nokogiri对它的评价:
doc.errors
# => [#<Nokogiri::XML::SyntaxError: Opening and ending tag mismatch: albums line 1 and classix_nouveaux>,
# #<Nokogiri::XML::SyntaxError: Extra content at the end of the document>]
那是因为:
<classix_nouveaux album="Night People"/>
和
<engligh_beat album="I Just Can't Stop It"/>
已终止。相反,它们应该是:
<classix_nouveaux album="Night People">
和
<engligh_beat album="I Just Can't Stop It">
您可以使用CSS或XPath选择器来查找完全匹配,甚至是子字符串匹配,但CSS或XPath都不了解&#34;范围&#34;日期,他们也不知道日期是什么,所以你必须提取所有节点,在这种情况下将日期值转换为Date对象或整数,然后比较范围:
date_range = 19800501..19820401
selected_albums = doc.search('//release_date').select { |rd| date_range.include?(rd['value'].to_i) }.map { |rd| rd.parent }
selected_albums.map(&:to_xml)
# => ["<aldo_nova album=\"aldo nova\">\n" +
# " <release_date value=\"19820401\"/>\n" +
# "</aldo_nova>",
# "<engligh_beat album=\"I Just Can't Stop It\">\n" +
# " <release_date value=\"19800501\"/>\n" +
# "</engligh_beat>"]
我认为您的XML设计很差,因为您的专辑应该有不同的标签名称。 <album>
应该是<albums>
的孩子。我建议这样的事情:
<collection>
<albums>
<album band="aldo nova" title="aldo nova" release_date="19820401"/>
<album band="classix nouveaux" title="Night People" release_date="19820501"/>
<album band="english beat" title="I Just Can't Stop It" release_date="19800501"/>
</albums>
</collection>
一旦XML采用标准形式,导航和搜索就会变得更容易:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<collection>
<albums>
<album band="aldo nova" title="aldo nova" release_date="19820401"/>
<album band="classix nouveaux" title="Night People" release_date="19820501"/>
<album band="english beat" title="I Just Can't Stop It" release_date="19800501"/>
</albums>
</collection>
EOT
doc.search('album').last['title'] # => "I Just Can't Stop It"
band = 'aldo nova'
doc.search("//album[@band='#{band}']").map { |a| a['title'] } # => ["aldo nova"]
并且搜索日期变得更加直接,因为找不到节点的父节点是不必要的:
date_range = 19800501..19820401
selected_albums = doc.search('album').select { |a| date_range.include?(a['release_date'].to_i) }
selected_albums.map(&:to_xml)
# => ["<album band=\"aldo nova\" title=\"aldo nova\" release_date=\"19820401\"/>",
# "<album band=\"english beat\" title=\"I Just Can't Stop It\" release_date=\"19800501\"/>"]
我建议您阅读一些关于XML本身的教程,因为如果数据没有逻辑和正确地表示,我们很容易将自己画成角落。