2017-05-08 71 views
-1

我通常使用Nokogiri作爲XML解析器。如何按日期範圍在Ruby中過濾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

請閱讀「[問]」,包括鏈接的頁面,「[mcve]」和「[Stack Overflow用戶需要多少研究工作?](http://meta.stackoverflow.com/questions/261592) 」。我們希望看到你的努力的證據。你嘗試了什麼?你搜索並沒有找到任何東西?你有沒有找到東西,但它沒有幫助?你有沒有嘗試寫代碼?如果不是,爲什麼?如果是這樣,那麼最小的代碼示例顯示了您嘗試的內容以及它爲什麼不起作用?沒有它,看起來你沒有嘗試並希望我們爲你寫信。 –

回答

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明白日期的「範圍」 ,它們也沒有的日期是什麼想法,所以你必須提取所有節點,轉換日期值到在這種情況下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本身的一些教程,因爲它很容易自己畫成的角落,如果數據不表示LOGI充分和正確地。