原帖很乱,希望这个编辑更清楚!。
我希望从哈希中生成XML,嵌套在数组中。我试图使用Nokogiri建设者并且不能完全正确。感谢Tin Man的一些帮助,我现在离我更近了一点,但我的例子远远不够清楚,无法破译。我也错过了一些关键信息。
这是我需要生成的XML:
<?xml version="1.0" encoding="UTF-8"?>
<Report Tool="FirewallParserv1">
<Firewalls>
<Firewall>
<issues>
<issue id="1" Category="2">
<Data mode="table">
<Row>
<column>ACL</columnumn>
<column>Rule</column>
<column>Source</column>
<column>Dest</column>
<column>Service</column>
<column>Log</column>
</Row>
<Row>
<column>inside_access_in</column>
<column>1</column>
<column>10.10.10.1</column>
<column>192.168.1.2</column>
<column>SMTP</column>
<column>YES</column>
</Row>
<Row>
<column>inside_access_in</column>
<column>2</column>
<column>172.16.2.1</column>
<column>192.168.100.10</column>
<column>HTTP</column>
<column>NO</column>
</Row>
<Row>
<column>inside_access_in</column>
<column>3</column>
<column>172.16.2.200</column>
<column>10.10.60.1</column>
<column>TELNET</column>
<column>NO</column>
</Row>
</Data>
</issue>
</issues>
</Firewall>
</Firewalls>
<Firewalls>
<Firewall>
<issues>
<issue id="2" Category="2">
<Data mode="table">
<Row>
<column>ACL</columnumn>
<column>Rule</column>
<column>Source</column>
<column>Dest</column>
<column>Service</column>
<column>Log</column>
</Row>
<Row>
<column>outside_access_in</column>
<column>8</column>
<column>195.92.195.92</column>
<column>192.168.1.2</column>
<column>SYSLOG</column>
<column>YES</column>
</Row>
<Row>
<column>outside_access_in</column>
<column>9</column>
<column>8.8.8.8</column>
<column>192.168.100.10</column>
<column>SSH</column>
<column>NO</column>
</Row>
<Row>
<column>outside_access_in</column>
<column>10</column>
<column>172.16.3.200</column>
<column>10.10.90.1</column>
<column>PROXY</column>
<column>NO</column>
</Row>
</Data>
</issue>
</issues>
</Firewall>
</Firewalls>
</Report>
到目前为止,我已经接近以下代码了,但是嵌套循环意味着我最终会对每个'问题'进行过多的迭代/重复,准确地说是三个。
rule_array1 = [
{:id => '1', :aclname => 'inside_access_in', :Rule => '1', :Source => '10.10.10.1', :Destination => '192.168.1.2', :port => 'SMTP', :Log => 'YES'},
{:id => '1', :aclname => 'inside_access_in', :Rule => '2', :Source => '172.16.2.1', :Destination => '192.168.100.10', :port => 'HTTP', :Log => 'NO'},
{:id => '1', :aclname => 'inside_access_in', :Rule => '3', :Source => '172.16.2.200', :Destination => '10.10.60.1', :port => 'TELNET', :Log => 'NO'}
]
rule_array2 = [
{:id => '2', :aclname => 'outside_access_in', :Rule => '8', :Source => '195.92.195.92', :Destination => '192.168.1.2', :port => 'SYSLOG', :Log => 'YES'},
{:id => '2', :aclname => 'outside_access_in', :Rule => '9', :Source => '8.8.8.8', :Destination => '192.168.100.10', :port => 'SSH', :Log => 'NO'},
{:id => '2', :aclname => 'outside_access_in', :Rule => '10', :Source => '172.16.3.200', :Destination => '10.10.90.1', :port => 'PROXY', :Log => 'NO'}
]
array_of_arrays = rule_array1, rule_array2
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
xml.Report('Tool' => 'FirewallParserv1') {
array_of_arrays.each do |outer|
outer.each do |rule|
xml.Firewalls {
xml.Firewall {
xml.issues {
xml.issue('id' => rule[:id], 'Category' => '2') {
xml.Data('mode' => "table") {
xml.Row {
xml.column("ACL")
xml.column("Rule")
xml.column("Source")
xml.column("Dest")
xml.column("Service")
xml.column("Log")
}
outer.each do |rule|
xml.Row {
xml.column(rule[:aclname])
xml.column(rule[:Rule])
xml.column(rule[:Source])
xml.column(rule[:Destination])
xml.column(rule[:port])
xml.column(rule[:Log])
}
end
}
}
}
}
}
end
end
}
end
puts builder.to_xml
如何在循环中循环并仅返回正确数量的“问题”?根据XML示例,应该有两个,每个都有三个规则,每个规则取自一个嵌套的哈希数组。
我希望这个问题现在更加清晰,并为原文中的混乱道歉。
更新:所以我设法基本上将我想要的东西拼凑起来:
issue_id = 1
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
xml.Report('Tool' => 'FirewallParserv1') {
xml.Firewalls {
xml.Firewall {
array_of_arrays.each do |outer|
xml.issues {
xml.issue('id' => issue_id, 'Category' => '2') {
xml.Data('mode' => "table") {
xml.Row {
xml.column("ACL")
xml.column("Rule")
xml.column("Source")
xml.column("Dest")
xml.column("Service")
xml.column("Log")
}
outer.each do |rule|
xml.Row {
xml.column(rule[:aclname])
xml.column(rule[:Rule])
xml.column(rule[:Source])
xml.column(rule[:Destination])
xml.column(rule[:port])
xml.column(rule[:Log])
}
end
}
}
}
issue_id +=1
end
}
}
}
end
puts builder.to_xml
为了达到这个目的,我不得不放弃从哈希中访问:id值,因为在我启动outer.each do |rule|
位之前我不访问该哈希值。作为一个临时的bodge,我只需为issue_id分配一个值,并在每个循环中递增它。有没有办法在迭代哈希之前得到:id值?或者我的逻辑是否存在缺陷?
编辑33: 似乎将ID值分配如下:
xml.issue('id' => outer[0][:id], 'Category' => '2') {
答案 0 :(得分:2)
规则一:正确保持缩进。有许多优秀的代码编辑器可以帮助您,无论是在编写时缩进/缩进,还是让您运行格式化程序。通过这样做,您可以更容易地看到循环和块中的问题。
您想要的代码示例是:
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
rule_array.each do |rule|
xml.Report('Tool' => 'FirewallParserv1') {
xml.Firewalls {
xml.Firewall {
xml.issues {
xml.issue('id' => rule[:id], 'Category' => '2') {
end
xml.Data('mode' => "table") {
xml.Row {
xml.columnumn("ACL")
xml.column("Rule")
xml.column("Source")
xml.column("Dest")
xml.column("Service")
xml.column("Log")
}
rule_array.each do |rule|
xml.Row {
xml.column(rule[:aclname])
xml.column(rule[:Rule])
xml.column(rule[:Source])
xml.column(rule[:Destination])
xml.column(rule[:port])
xml.column(rule[:Log])
}
end
}
}
}
}
}
}
end
让vim重新获得它后,我得到了:
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
rule_array.each do |rule|
xml.Report('Tool' => 'FirewallParserv1') {
xml.Firewalls {
xml.Firewall {
xml.issues {
xml.issue('id' => rule[:id], 'Category' => '2') {
end
xml.Data('mode' => "table") {
xml.Row {
xml.columnumn("ACL")
xml.column("Rule")
xml.column("Source")
xml.column("Dest")
xml.column("Service")
xml.column("Log")
}
rule_array.each do |rule|
xml.Row {
xml.column(rule[:aclname])
xml.column(rule[:Rule])
xml.column(rule[:Source])
xml.column(rule[:Destination])
xml.column(rule[:port])
xml.column(rule[:Log])
}
end
}
}
}
}
}
}
end
puts builder.to_xml
立即显示存在问题,因为XML生成代码(如要输出的XML)必须正确嵌套。
调整XML根目录和与end
相关联的rule_array
以便它们正确嵌套导致:
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
xml.Report('Tool' => 'FirewallParserv1') {
rule_array.each do |rule|
xml.Firewalls {
xml.Firewall {
xml.issues {
xml.issue('id' => rule[:id], 'Category' => '2') {
xml.Data('mode' => "table") {
xml.Row {
xml.columnumn("ACL")
xml.column("Rule")
xml.column("Source")
xml.column("Dest")
xml.column("Service")
xml.column("Log")
}
rule_array.each do |rule|
xml.Row {
xml.column(rule[:aclname])
xml.column(rule[:Rule])
xml.column(rule[:Source])
xml.column(rule[:Destination])
xml.column(rule[:port])
xml.column(rule[:Log])
}
end
}
}
}
}
}
end
}
end
但那不是很有效率。稍微调整一下我就会使用:
#!/usr/bin/env ruby
require 'nokogiri'
HEADERS = %w(ACL Rule Source Dest Service Log)
FIELDS = %i(aclname Rule Source Destination port Log)
rule_array = [
{:id => '1', :aclname => 'inside_access_in', :Rule => '1', :Source => '10.10.10.1', :Destination => '192.168.1.2', :port => 'SMTP', :Log => 'YES'},
{:id => '2', :aclname => 'inside_access_in', :Rule => '2', :Source => '172.16.2.1', :Destination => '192.168.100.10', :port => 'HTTP', :Log => 'NO'},
{:id => '3', :aclname => 'inside_access_in', :Rule => '3', :Source => '172.16.2.200', :Destination => '10.10.60.1', :port => 'TELNET', :Log => 'NO'}
]
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
xml.Report('Tool' => 'FirewallParserv1') {
rule_array.each do |rule|
xml.Firewalls {
xml.Firewall {
xml.issues {
xml.issue('id' => rule[:id], 'Category' => '2') {
xml.Data('mode' => "table") {
xml.Row {
HEADERS.each do |h|
xml.column(h)
end
}
xml.Row {
rule.values_at(*FIELDS).each do |f|
xml.column(f)
end
}
}
}
}
}
}
end
}
end
puts builder.to_xml
运行时输出:
# >> <?xml version="1.0" encoding="UTF-8"?>
# >> <Report Tool="FirewallParserv1">
# >> <Firewalls>
# >> <Firewall>
# >> <issues>
# >> <issue id="1" Category="2">
# >> <Data mode="table">
# >> <Row>
# >> <column>ACL</column>
# >> <column>Rule</column>
# >> <column>Source</column>
# >> <column>Dest</column>
# >> <column>Service</column>
# >> <column>Log</column>
# >> </Row>
# >> <Row>
# >> <column>inside_access_in</column>
# >> <column>1</column>
# >> <column>10.10.10.1</column>
# >> <column>192.168.1.2</column>
# >> <column>SMTP</column>
# >> <column>YES</column>
# >> </Row>
# >> </Data>
# >> </issue>
# >> </issues>
# >> </Firewall>
# >> </Firewalls>
# >> <Firewalls>
# >> <Firewall>
# >> <issues>
# >> <issue id="2" Category="2">
# >> <Data mode="table">
# >> <Row>
# >> <column>ACL</column>
# >> <column>Rule</column>
# >> <column>Source</column>
# >> <column>Dest</column>
# >> <column>Service</column>
# >> <column>Log</column>
# >> </Row>
# >> <Row>
# >> <column>inside_access_in</column>
# >> <column>2</column>
# >> <column>172.16.2.1</column>
# >> <column>192.168.100.10</column>
# >> <column>HTTP</column>
# >> <column>NO</column>
# >> </Row>
# >> </Data>
# >> </issue>
# >> </issues>
# >> </Firewall>
# >> </Firewalls>
# >> <Firewalls>
# >> <Firewall>
# >> <issues>
# >> <issue id="3" Category="2">
# >> <Data mode="table">
# >> <Row>
# >> <column>ACL</column>
# >> <column>Rule</column>
# >> <column>Source</column>
# >> <column>Dest</column>
# >> <column>Service</column>
# >> <column>Log</column>
# >> </Row>
# >> <Row>
# >> <column>inside_access_in</column>
# >> <column>3</column>
# >> <column>172.16.2.200</column>
# >> <column>10.10.60.1</column>
# >> <column>TELNET</column>
# >> <column>NO</column>
# >> </Row>
# >> </Data>
# >> </issue>
# >> </issues>
# >> </Firewall>
# >> </Firewalls>
# >> </Report>
看起来有点明智,虽然它不是非常有效的XML,但是如果没有缺失但又非常重要的期望输出,那么它就足够了。
请注意,Nokogiri将在哈希中使用Ruby的符号键,有助于减少哈希定义中的视觉噪音。