在构建 xml 时引用特定块



我正在使用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或其他任何东西都有可能吗?

与其

在构建节点时尝试保留节点的句柄,不如使用 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|

相关内容

  • 没有找到相关文章

最新更新