我正在制作一个TCL程序,该程序将返回交换机下的设备数组列表。该定义是一个读取的XML文件。生成的XML条目列表使用递归过程进行解析,设备属性放在数组中。
然后将每个数组放在一个列表中并反射回调用者。我的问题是,当我打印出设备列表时,每次打印出添加到列表中的最后一个设备。列表的内容都是重复的。
注意:我使用优秀的proc,' xml2list'这是在这里找到的。对不起,我忘了是谁提交了这个。
以下代码说明了问题:
source C:/src/tcl/xml2list.tcl
# Read and parse XML file
set fh [open C:/data/tcl/testfile.xml r]
set myxml [read $fh]
set mylist [xml2list $myxml]
array set mydevice {}
proc devicesByName { name thelist list_to_fill} {
global mydevice
global set found_sw 0
upvar $list_to_fill device_arr
foreach switch [lindex $thelist 2] {
set atts [lindex $switch 1]
if { [lindex $switch 0] == "Switch" } {
if { $name == [lindex $atts 3] } {
set found_sw 1
puts "==== Found Switch: $name ===="
} else {
set found_sw 0
}
} elseif { $found_sw == 1 && [string length [lindex $atts 3]] > 0 } {
set mydevice(hdr) [lindex $switch 0]
set mydevice(port) [lindex $atts 1]
set mydevice(name) [lindex $atts 3]
set mydevice(type) [lindex $atts 5]
puts "Device Found: $mydevice(name)"
set text [lindex $switch 2]
set mydevice(ip) [lindex [lindex $text 0] 1]
lappend device_arr mydevice
}
devicesByName $name $switch device_arr
}
}
#--- Call proc here
# set a local array var and send to the proc
set device_arr {}
devicesByName "Switch1" $mylist device_arr
# read out the contents of the list of arrays
for {set i 0} {$i<[llength $device_arr]} {incr i} {
upvar #0 [lindex $device_arr $i] temp
if {[array exists temp]} {
puts "\[$i\] Device: $temp(name)-$temp(ip)"
}
}
XML文件在这里:
<Topology>
<Switch ports="48" name="Switch1" ip="10.1.1.3">
<Device port="1" name="RHEL53-Complete1" type="host">10.1.1.10</Device>
<Device port="2" name="Windows-Complete1" type="host">10.1.2.11</Device>
<Device port="3" name="Solaris-Complete1" type="host">10.1.2.12</Device>
</Switch>
<Switch ports="36" name="Switch2" ip="10.1.1.4">
<Device port="1" name="Windows-Complete2" type="host">10.1.3.10</Device>
</Switch>
<Router ports="24" name="Router1" ip="10.1.1.2">
<Device port="1" name="Switch1" type="switch">10.1.1.3</Device>
<Device port="2" name="Switch2" type="switch">10.1.1.4</Device>
</Router>
</Topology>
如果我的代码块看起来很糟糕,请原谅。我按照指示阅读了它们,但它看起来并不正确。我无法解决它,所以只是发布了。
提前致谢...
答案 0 :(得分:2)
tcl中的数组不是值。因此,它们的行为不像常规变量。事实上它们就像文件句柄或套接字一样特殊。
您不能将数组分配给这样的列表。这样做的:
lappend device_arr mydevice
只需将字符串"mydevice"
附加到列表device_arr
即可。该字符串恰好是全局变量的名称,以便稍后可以使用该字符串来访问该全局变量。
要构建您想要的键值数据结构dict。您可以将dict视为一个特殊列表,其中包含以下格式的偶数元素:{key value key value}
。实际上,在引入dict
之前,这个数据结构甚至可以在非常旧的tcl版本上工作,因为tcl中的foreach
循环可以用来处理键值对。
所以你想要的是在每个循环中创建一个新的$mydevice
dict并使用[dict set]
来分配值。
或者,您可以保留大部分代码并将您的lappend更改为:
lappend device_arr [array get mydevice]
这是有效的,因为[array get]
返回一个可以被视为dict的键值列表。您可以稍后使用dict
命令访问数据。
答案 1 :(得分:2)
数组变量不能用作值。要将one的内容放入list元素,将其发送到proc,将其写入文件等,使用array get
将其转换为list表单(键,值,键,值...)。
lappend device_arr [array get mydevice]
要在以后使用它,请将列表写回array set
的数组。
foreach device_l $device_arr {
#array unset device
array set device $device_l
puts "$device(name)-$device(ip)"
}
请注意array set
不会删除目标数组中的旧键,因此如果在循环中使用它并且键名不总是相同,则需要每次迭代清除该数组。
答案 2 :(得分:0)
您可以使用数组以两种方式存储此信息。首先是作为多维数组,在这种情况下是三维数组,第二个是存储列表的一维数组,该列表可以稍后容易地转换为数组以便稍后访问数据。
对于3d数组,键是Switch Name,device_port,dataname,你可以将错误的临时myDevice和lappend代码更改为
# attr is a list of { attributename1 value1 ... attributenameN valueN}
array set temp $attr
set port $temp(port)
set text [lindex $switch 2]
set ip [lindex [lindex $text 0] 1]
# name already set to "Switch1" etc
foreach f [array names temp ] {
set device_arr($name,$port,$f) $temp($f)
}
set device_arr($name,$port,ip) $ip
array unset temp
此代码导致以下结果(当parray device_arr
时)parray device_arr
device_arr(Switch1,1,name) "Switch1"
device_arr(Switch1,1,port) 1
device_arr(Switch1,1,type) "RedHat .."
device_arr(Switch1,1,ip) 10..
device_arr(Switch1,2,name) "Switch1"
device_arr(Switch1,2,port) 1
device_arr(Switch1,2,type) "RedHat .."
device_arr(Switch1,2,ip) 10..
...
device_arr(Switch2,1,name) "Switch1"
device_arr(Switch2,1,port) 1
device_arr(Switch2,1,type) "Windows Complete"
device_arr(Switch2,1,ip) 10..
....
找到Switch1 port2的ip,你会:
puts "the ip of Switch1 port 2 is $device_arr(Switch1,2,ip)"
请注意大量数据重复,但您可以直接访问所有数据,而无需像下一个方案那样进入中间步骤来获取数据
# attr is a list of { attributename1 value1 ... attributenameN valueN}
set data $attr
array set temp $attr
set text [lindex $switch 2]
set ip [lindex [lindex $text 0] 1]
lappend data ip $ip
set key "$name,$temp(port)"
# name already set to "Switch1" etc
set device_arr($name,$port) $data
array unset temp
做一个parray device_arr给出:
device_arr(Switch1,1) { port "1" name "RHEL53-Complete1" type "host" ip 10.1.1.10 }
device_arr(Switch1,2) { port "2" name "Windows-Complete1" type "host" ip 10.1.2.11}
....
找到swtich1端口2的ip,你会
array set temp $device_array(Switch1,2)
puts "ip of device 2 is $temp(ip)"