2014-05-24 66 views
0

有一個Ruby的REXML元素象下面這樣:如何從REXML元素中獲取所有葉單元,並將它們保存到數組中?

<a_1> 
    <Tests> 
    <test enabled='1'>trans </test> 
    <test enabled='1'>ac </test> 
    <test enabled='1'>dc </test> 
    </Tests> 
    <Corners> 
    <corner enabled='0'>default</corner> 
    <corner enabled='1'>C0 </corner> 
    </Corners> 
</a_1> 

我想找到的所有葉元素,所以結果應該是:

<test enabled='1'>trans </test> 
<test enabled='1'>ac </test> 
<test enabled='1'>dc </test> 
<corner enabled='0'>default</corner> 
<corner enabled='1'>C0 </corner> 

我的代碼是:

require 'rexml/document' 
include REXML 

def getAllLeaf(xmlElement) 
    if xmlElement.has_elements? 
    xmlElement.elements.each {|e| 
     getAllLeaf(e) 
    } 
    else 
    return xmlElement 
    end 
end 

它工作正常,並在屏幕上顯示正確的輸出。但是,當我嘗試將結果保存到數組時,發現我遇到了問題,因爲此遞歸過程。因此,如果有一種方法可以將此輸出保存到一個可以在以後使用的數組中,那麼我該如何做?

我掙扎了一個遞歸的方式做到這一點,雖然有點奇怪,我想和大家分享一下:

def getAllLeaf(eTop,aTemp=Element.new("LeafElements")) 
    if eTop.has_elements? 
    eTop.elements.each {|e| 
     getAllLeaf(e,aTemp) 
    } 
    else 
    aTemp<< eTop.dup 
    end 
    return aTemp 
end 

回答

0

它工作正常,並沒有在屏幕上顯示正確的輸出。

實際上,代碼在任何地方都沒有輸出。在任何情況下,你的遞歸功能不起作用,你可以看到,如果你打電話給你方法的元素< Tests><Tests>看起來是這樣的:

<Tests> 
    <test enabled='1'> 
     <HELLO>world</HELLO> 
    </test> 
    <test enabled='1'>ac </test> 
    <test enabled='1'>dc </test> 
    </Tests> 

你的遞歸方法不起作用,因爲當你寫:

xmlElement.elements.each {|e| 

each()方法返回剩下的東西,即xmlElement.elements。鑑於你的XML,你的遞歸方法等效於:

def getAllLeaf(xmlElement) 
    xmlElement.elements.each {|e| 
     "blah" #your code here has no effect on what each() returns. 
    } 
end 

..這相當於:

def getAllLeaf(xmlElement) 
    return xmlElement.elements 
end 

你想堅持使用遞歸?這是更簡單的搜索元素的所有元素無子女:

require "rexml/document" 
include REXML 

xml = <<'END_OF_XML' 
<a_1> 
    <Tests> 
    <test enabled='1'>trans </test> 
    <test enabled='1'>ac </test> 
    <test enabled='1'>dc </test> 
    </Tests> 
    <Corners> 
    <corner enabled='0'>default</corner> 
    <corner enabled='1'>C0 </corner> 
    </Corners> 
</a_1> 
END_OF_XML 

doc = Document.new xml 
root = doc.root 

XPath.each(root, "//*") do |element| 
    if not element.has_elements? 
    enabled = element.attributes['enabled'] 
    text = element.text 
    puts "#{enabled} ... #{text}" 
    end 
end 

--output:-- 
1 ... trans 
1 ... ac 
1 ... dc 
0 ... default 
1 ... C0 

或者,如果所有的葉元素與「已啓用」屬性的唯一要素,你應該這樣做:

XPath.each(root, "//*[@enabled]") do |element| 
    enabled = element.attributes['enabled'] 
    text = element.text 
    puts "#{enabled} ... #{text}" 
end 

甚至還有一個神祕的XPath,將直接選擇元素無子元素:

XPath.each(root, "//*[not(*)]") do |element| 
    enabled = element.attributes['enabled'] 
    text = element.text 
    puts "#{enabled} ... #{text}" 
end 

此外,有你使用引入nokogiri寶石考慮?這幾乎是ruby的標準XML/HTML解析器。

+0

感謝7stud,您的解決方案是不錯的,並在我身邊完美的工作。 – user3672656

+0

感謝7stud,爲您的解釋和解決方案。解決方案很好,在我身邊完美。抱歉,我是Ruby新手,剛開始使用REXML,並沒有想到XPath。那個看起來非常強大,我想我應該多學一點。 – user3672656

+0

我不知道你對xml解析知道多少,但是所有文本都被包含在文本節點中。該規則也適用於換行符。例如,在標籤後面的原始xml中,有一個換行符。不幸的是,當你遍歷文檔中的所有節點時,文本節點與元素不同,文本節點導致錯誤,如「\ n」沒有名爲has_elements的方法?只要執行'p root.to_a'來查看root的所有直接子項就可以看到我在說什麼。關於Xpath的好處在於它僅提取指定的標記,而省去了換行符節點。 – 7stud

相關問題