这与this question 非常相似。这是基于sris's answer的修改版本:
paths = [
"nodeA1",
"nodeA1/nodeB1/nodeC1",
"nodeA1/nodeB1/nodeC1/nodeD1/nodeE1",
"nodeA1/nodeB1/nodeC2",
"nodeA1/nodeB2/nodeC2",
"nodeA3/nodeB2/nodeC3"
]
tree = {}
paths.each do |path|
current = tree
path.split("/").inject("") do |sub_path,dir|
sub_path = File.join(sub_path, dir)
current[sub_path] ||= {}
current = current[sub_path]
sub_path
end
end
def make_tree(prefix, node)
tree = ""
node.each_pair do |path, subtree|
tree += "#{prefix}<#{File.basename(path)}"
if subtree.empty?
tree += "/>\n"
else
tree += ">\n"
tree += make_tree(prefix + "\t", subtree) unless subtree.empty?
tree += "#{prefix}</#{File.basename(path)}>\n"
end
end
tree
end
xml = make_tree "", tree
print xml
编辑:
这是一个使用 Nokogiri 构建实际 XML 文档的修改版本。我认为它实际上比字符串版本更容易遵循。我还删除了File 的使用,因为您实际上并不需要它来满足您的需求:
require 'nokogiri'
paths = [
"nodeA1",
"nodeA1/nodeB1/nodeC1",
"nodeA1/nodeB1/nodeC1/nodeD1/nodeE1",
"nodeA1/nodeB1/nodeC2",
"nodeA1/nodeB2/nodeC2",
"nodeA3/nodeB2/nodeC3"
]
tree = {}
paths.each do |path|
current = tree
path.split("/").each do |name|
current[name] ||= {}
current = current[name]
end
end
def make_tree(node, curr = nil, doc = Nokogiri::XML::Document.new)
#You need a root node for the XML. Feel free to rename it.
curr ||= doc.root = Nokogiri::XML::Node.new('root', doc)
node.each_pair do |name, subtree|
child = curr << Nokogiri::XML::Node.new(name, doc)
make_tree(subtree, child, doc) unless subtree.empty?
end
doc
end
xml = make_tree tree
print xml
编辑 2:
是的,在 Ruby 1.8 中确实不能保证哈希值保持插入顺序。如果这是一个问题,有办法解决它。这是一个保留顺序但不打扰递归并且更简单的解决方案:
require 'nokogiri'
paths = [
"nodeA1",
"nodeA1/nodeB1/nodeC1",
"nodeA1/nodeB1/nodeC1/nodeD1/nodeE1",
"nodeA1/nodeB1/nodeC2",
"nodeA1/nodeB2/nodeC2",
"nodeA3/nodeB2/nodeC3"
]
doc = Nokogiri::XML::Document.new
doc.root = Nokogiri::XML::Node.new('root', doc)
paths.each do |path|
curr = doc.root
path.split("/").each do |name|
curr = curr.xpath(name).first || curr << Nokogiri::XML::Node.new(name, doc)
end
end
print doc