2012-05-17 44 views
1

我使用Ruby構建將表示網絡圖的gexf格式的XML結構。該圖由幾個嵌套節點層組成。我們的想法是解析看起來是這樣的文件:構建xml時引用特定塊

| top node | middle node | bottom node | 
| a  |  1  | "name1" | 
| b  |  1  | "name6" | 
| a  |  2  | "name3" | 
| b  |  2  | "name8" | 
| b  |  1  | "name5" | 
| a  |  1  | "name2" | 
| b  |  2  | "name7" | 
| a  |  2  | "name4" | 

並把它變成這樣:

<node id = a label = "top node"> 
    <node id = 1 label = "middle node"> 
    <node id = name1 label = "bottom node"/> 
    <node id = name2 label = "bottom node"/> 
    </node>  
    <node id = 2 label = "middle node">  
    <node id = name3 label = "bottom node"/> 
    <node id = name4 label = "bottom node"/> 
    </node> 
</node> 
<node id = b label = "top node"> 
    <node id = 1 label = "middle node"> 
    <node id = name5 label = "bottom node"/> 
    <node id = name6 label = "bottom node"/> 
    </node>  
    <node id = 2 label = "middle node">  
    <node id = name7 label = "bottom node"/> 
    <node id = name8 label = "bottom node"/> 
    </node> 
</node> 

正如你所看到的,因爲文件中的行是不以任何特定的順序,我需要能夠在構建XML文件時參考每個節點和子節點。

如果我的問題是目前尚不清楚,當我讀線:

| b  |  1  | "name6" | 

我需要能夠告訴建設者堅持這個節點「name6」內部「頂部節點B」和「中間節點1「。建築師或者Nokogiri的建築師或者其他什麼都可以嗎?

+1

這可能與Nokogiri。你有什麼嘗試? –

回答

0

,而不是試圖保持一個手柄上的節點爲您打造它們,使用查詢引入nokogiri能力的CSS(或XPath)來尋找已添加到文檔節點,當你需要他們:

require 'nokogiri' 

# Create an array of the top/middle/bottom node ids 
rows = File.readlines('my.data')[1..-1].map{ |row| row.scan(/[^|\s"]+/) } 

# Look underneath a parent node for another node with a specific id 
# If you can't find one, create one (with the label) and return it. 
def find_or_create_on(parent,id,label) 
    parent.at("node[id='#{id}']") or 
    parent.add_child("<node id='#{id}' label='#{label}' />")[0] 
end 

# Since an XML document can only ever have one root node, 
# and your data can have many, let's wrap them all in a new document 
root = Nokogiri.XML('<root></root>').root 

# For each triplet, find or create the nodes you need, in order 
# (When iterating an array of arrays, you can automagically convert 
# each item in the sub-array to a named variable.) 
rows.each do |top_id, mid_id, bot_id| 
    top = find_or_create_on(root, top_id, 'top node' ) 
    mid = find_or_create_on(top, mid_id, 'middle node') 
    bot = find_or_create_on(mid, bot_id, 'bottom node') 
end 

puts root 
#=> <root> 
#=> <node id="a" label="top node"> 
#=>  <node id="1" label="middle node"> 
#=>  <node id="name1" label="bottom node"/> 
#=>  <node id="name2" label="bottom node"/> 
#=>  </node> 
#=>  <node id="2" label="middle node"> 
#=>  <node id="name3" label="bottom node"/> 
#=>  <node id="name4" label="bottom node"/> 
#=>  </node> 
#=> </node> 
#=> <node id="b" label="top node"> 
#=>  <node id="1" label="middle node"> 
#=>  <node id="name6" label="bottom node"/> 
#=>  <node id="name5" label="bottom node"/> 
#=>  </node> 
#=>  <node id="2" label="middle node"> 
#=>  <node id="name8" label="bottom node"/> 
#=>  <node id="name7" label="bottom node"/> 
#=>  </node> 
#=> </node> 
#=> </root> 

請注意,您可能需要重新考慮您對屬性id的使用情況,因爲您在此處提供的值既不是a)在整個文檔中全局唯一,也不是b)有效標識符(數字不能是XML中的ID值)。

另外,您的輸出中有一些子節點的排序順序與它們在源數據中出現的順序不同。例如,b/2/name8出現在b/2/name7之前,所以我的解決方案按此順序創建它們。如果你需要他們排序,然後排序rows第一,例如:

rows.sort.each do |top_id,mid_id,bot_id| 
+0

啊,謝謝!這是有道理的。我使用「id」的原因是這是gexf格式的工作原理。每個節點都有屬性「id」,它應該是唯一的標識符。我的問題中的標識符是示例。在真實情況下,我確定它們是獨一無二的。而我的源數據被這樣格式化的原因是爲了表明它沒有任何順序。 – hriundel

+0

我的榮幸;我希望它有幫助。 – Phrogz