Это очень похоже на этот вопрос . Вот модифицированная версия, основанная на ответе sris :
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
Edit:
Вот модифицированная версия, которая создает настоящий XML-документ с использованием Nokogiri. Я думаю, что на самом деле легче следовать, чем строковая версия. Я также исключил использование 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