1

Ruby を使用して、ネットワーク グラフを表す gexf 形式の 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」内に固定するようビルダーに指示できるようにする必要があります。Builder や Nokogiri の Builder などで可能なことはありますか?

4

1 に答える 1

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) 有効な識別子 (ID数値を XML の値にすることもできません) でもないため、 attribute の使用方法を再検討することをお勧めします。

また、出力には、ソース データに表示される順序とは異なる順序で並べ替えられたいくつかの子ノードがあります。たとえば、 のb/2/name8前に表示されるb/2/name7ため、私のソリューションではこの順序でそれらを作成します。それらを並べ替える必要がある場合は、rows最初に並べ替えます。

rows.sort.each do |top_id,mid_id,bot_id|
于 2012-05-18T15:49:02.610 に答える