2013-02-28 51 views
2

我有以下XML:除了實際元素之外,Nokogiri XML.children還返回格式化元素。如何避免這種情況?

<attributes> 
    <intelligence>27</intelligence> 
    <memory>21</memory> 
    <charisma>17</charisma> 
    <perception>17</perception> 
    <willpower>17</willpower> 
</attributes> 

我想分析如下:

intelligence: 27, memory: 21, charisma: 17, perception: 17, willpower: 17 

當我嘗試此代碼:

def get_attributes(api) 
    attributes = [] 
    api.xpath("//attributes").children.each do |attribute| 
    name = attribute.name.tr('^A-Za-z0-9', '') 
    text = attribute.text 
    attributes << "#{name}: #{text}" 
    end 
    attributes 
end 

我與新行數據結果(因爲的格式):每個偶數小孩:

#(Text "\n  ") 
#(Element:0x3ffe166fdb9c { name = "intelligence", children = [ #(Text "20")] }) 
#(Text "\n  ") 
#(Element:0x3ffe166f71ac { name = "memory", children = [ #(Text "25")] }) 
#(Text "\n  ") 
#(Element:0x3ffe166f3818 { name = "charisma", children = [ #(Text "23")] }) 
#(Text "\n  ") 
#(Element:0x3ffe166f0604 { name = "perception", children = [ #(Text "16")] }) 
#(Text "\n  ") 
#(Element:0x3ffe166b52e8 { name = "willpower", children = [ #(Text "15")] }) 
#(Text "\n ") 

Nokogiri中有沒有一種方法可以跳過這些「僅格式化」的孩子?還是我必須手動遍歷奇數編號的元素?

我希望api.xpath("//attributes").children導航實際的孩子,而不是格式文本。

回答

6

children方法將返回目標節點的所有子節點包括文本節點。如果你只是希望所有的元素節點的孩子,你可以使用你的* XPath查詢指定:

def attributes(api) 
    api.xpath('//attributes/*').each_with_object([]) do |n, ary| 
    ary << "#{n.name}: #{n.text}" 
    end 
end 

這將返回一個字符串數組與格式name: value,這是它看起來像你想要的。

+0

Xpath FTW。我知道有更好的辦法... – 2013-02-28 16:52:49

1

我認爲簡短答案是「否」。但是,您可以輕鬆做到:

if attribute.element? 
    name = attribute.name.tr('^A-Za-z0-9', '') 
    text = attribute.text 
    attributes << "#{name}: #{text}" 
end 

可以獲得理想的效果。另外,這個版本可能會稍微更具可讀性:

if ! attribute.text? 
    name = ... 
    ... 
end 
1

如果你只是想爲孩子文本節點,使用:

require 'nokogiri' 
require 'pp' 

doc = Nokogiri::HTML(<<EOT) 
<attributes> 
    <intelligence>27</intelligence> 
    <memory>21</memory> 
    <charisma>17</charisma> 
    <perception>17</perception> 
    <willpower>17</willpower> 
</attributes> 
EOT 

doc.at('attributes').children.map(&:text) 

將返回:

["27", "21", "17", "17", "17"] 

從那裏,你可以很容易做到:

'intelligence: %02d, memory: %02d, charisma: %02d, perception: %02d, willpower: %02d' % doc.at('attributes').children.map(&:text) 
=> "intelligence: 27, memory: 21, charisma: 17, perception: 17, willpower: 17" 

如果你希望它是更有條理一點,你可以這樣做:

doc.at('attributes').children.each_with_object({}){ |o,h| h[o.name] = o.text } 
=> {"intelligence"=>"27", "memory"=>"21", "charisma"=>"17", "perception"=>"17", "willpower"=>"17"} 

或者:

doc.at('attributes').children.each_with_object({}){ |o,h| h[o.name.to_sym] = o.text } 
=> {:intelligence=>"27", :memory=>"21", :charisma=>"17", :perception=>"17", :willpower=>"17"} 

doc.at('attributes').children 
=> [#<Nokogiri::XML::Element:0x3fc3245fb8fc name="intelligence" children=[#<Nokogiri::XML::Text:0x3fc3245fb6f4 "27">]>, #<Nokogiri::XML::Element:0x3fc3245fb4ec name="memory" children=[#<Nokogiri::XML::Text:0x3fc3245fb2e4 "21">]>, #<Nokogiri::XML::Element:0x3fc3245fb0dc name="charisma" children=[#<Nokogiri::XML::Text:0x3fc3245faed4 "17">]>, #<Nokogiri::XML::Element:0x3fc3245fecb4 name="perception" children=[#<Nokogiri::XML::Text:0x3fc3245feaac "17">]>, #<Nokogiri::XML::Element:0x3fc3245fe8a4 name="willpower" children=[#<Nokogiri::XML::Text:0x3fc3245fe69c "17">]>] 
+0

使用你的第一個單線我仍然得到一個回車字符元素(但它非常接近):'{:text =>「\ n」,:intelligence =>「20」,:memory =>「25 「::charisma =>」23「,:perception =>」16「,:willpower =>」15「}' – Ecnalyr 2013-02-28 15:44:14

+0

如果您收到回車,則說明有錯或遺漏。你可以看到上面的代碼沒有做任何特殊的事情,而且CR也不存在。文本節點存在於孩子外面,但他們沒有被返回。 – 2013-02-28 15:47:07

+0

Nokogiri目前在v1.5.6。如果你不是最新的版本,你可以嘗試使用'gem update nokogiri'來更新它。 – 2013-02-28 15:51:40

相關問題