ElementTree 缺少获取第一个子节点的函数
我正在用Python写一个解析器,用来解析一个XML文件。为了做到这一点,我需要获取标签名,但在获取标签名的时候,除了标签名,我还得到了命名空间。同时,我还需要在很多地方获取第一个子节点,但在这个库(Elementtree)中我找不到相关的属性。我搜索了很多,但还是找不到怎么只获取标签名而不带命名空间的值,以及如何获取第一个子节点。试用的input.xml文件如下:
<?xml version="1.0"?>
<nf:rpc-reply xmlns:nf="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns="http://www.cisco.com/nxos:1.0:ip">
<nf:data>
<show>
<ip>
<interface>
<__XML__BLK_Cmd_ip_show_interface_command_brief>
<__XML__OPT_Cmd_ip_show_interface_command_operational>
<__XML__OPT_Cmd_ip_show_interface_command_vrf>
<__XML__OPT_Cmd_ip_show_interface_command___readonly__>
<__readonly__>
<TABLE_intf>
<ROW_intf>
<vrf-name-out>default</vrf-name-out>
<intf-name>Vlan10</intf-name>
<prefix>9.1.1.1</prefix>
<ip-disabled>FALSE</ip-disabled>
<iod>104</iod>
<proto-state>TRUE</proto-state>
<link-state>TRUE</link-state>
<admin-state>TRUE</admin-state>
</ROW_intf>
<ROW_intf>
<vrf-name-out>default</vrf-name-out>
<intf-name>Vlan23</intf-name>
<prefix>23.1.1.9</prefix>
<ip-disabled>FALSE</ip-disabled>
<iod>103</iod>
<proto-state>TRUE</proto-state>
<link-state>TRUE</link-state>
<admin-state>TRUE</admin-state>
</ROW_intf>
<ROW_intf>
<vrf-name-out>default</vrf-name-out>
<intf-name>Po1</intf-name>
<prefix>4.9.1.2</prefix>
<ip-disabled>FALSE</ip-disabled>
<iod>111</iod>
<proto-state>TRUE</proto-state>
<link-state>TRUE</link-state>
<admin-state>TRUE</admin-state>
</ROW_intf>
<ROW_intf>
<vrf-name-out>default</vrf-name-out>
<intf-name>Po2</intf-name>
<prefix>5.9.1.2</prefix>
<ip-disabled>FALSE</ip-disabled>
<iod>112</iod>
<proto-state>TRUE</proto-state>
<link-state>TRUE</link-state>
<admin-state>TRUE</admin-state>
</ROW_intf>
<ROW_intf>
<vrf-name-out>default</vrf-name-out>
<intf-name>Po3</intf-name>
<prefix>6.9.1.2</prefix>
<ip-disabled>FALSE</ip-disabled>
<iod>113</iod>
<proto-state>TRUE</proto-state>
<link-state>TRUE</link-state>
<admin-state>TRUE</admin-state>
</ROW_intf>
</TABLE_intf>
</__readonly__>
</__XML__OPT_Cmd_ip_show_interface_command___readonly__>
</__XML__OPT_Cmd_ip_show_interface_command_vrf>
</__XML__OPT_Cmd_ip_show_interface_command_operational>
</__XML__BLK_Cmd_ip_show_interface_command_brief>
</interface>
</ip>
</show>
</nf:data>
</nf:rpc-reply>
我正在写的代码(还在完成中,给出这个代码只是为了让你了解我想要得到的输出):
import xml.etree.ElementTree as ET
print "before skip()"
def skip(root):
print "rootname.tag in skip == %s" %(root.tag)
if(root.tag == "readonly"): // here if I compare with the namespace then returns the value
print "skip -> if"
return root
else:
print "skip-> else"
root = root[0]
print "new root %s" %root
return skip(root)
xmlDoc = ET.parse("trialinput.xml")
dict = {}
print "accessing the root"
root = xmlDoc.getroot()
print "rootname == %s" %root.tag
pointerOfReadonly = skip(root)
print "pointerOfReadonly.tag %s" %pointerOfReadonly.tag
print "accessing child of readonly"
tableInitiationPointer = pointerOfReadonly[0] // Here how to get the first child of readonly tag?
#print "accessing children of table"
#allRows = tableInitiationPointer.childNodes
Print "no of rows in the table = %s" %tableInitiationPointer.len("ROW_intf")// Returning none due to above non ability to find the tag
for row in tableInitiationPointer:
for subrows in row:
key = subrows.tag
value = subrows.value
dict[key]=value
2 个回答
0
你缺少的是正确使用命名空间的知识。
因为你的xml文件里有命名空间,所以节点会带上这些命名空间,ET(ElementTree)会连同tag
一起返回命名空间。
试试下面的方式来提取正确的节点:
xmlDoc = ET.parse("trialinput.xml")
dict = {}
print "accessing the root"
root = xmlDoc.getroot()
print "rootname == %s" %root.tag
pointerOfReadonly = root.findall(".//{http://www.cisco.com/nxos:1.0:ip}__readonly__")
print pointerOfReadonly
前两个节点,rpc-reply
和data
,会包含命名空间"urn:ietf:params:xml:ns:netconf:base:1.0"
,其他的节点会包含"http://www.cisco.com/nxos:1.0:ip"
想了解xpath
的语法和用法,可以查看这份文档
所以,当你搜索节点__readonly__
时,需要在findall()
方法中明确指定命名空间,像这样:
pointerOfReadonly = root.findall(".//{http://www.cisco.com/nxos:1.0:ip}__readonly__")
print pointerOfReadonly
这会打印出所有找到的节点列表(在我们的例子中只有一个):
[<Element '{http://www.cisco.com/nxos:1.0:ip}__readonly__' at 0x20b4990>]
接下来,你需要用类似的方法去搜索其他节点。比如,如果你想找节点ROW_intf
,可以这样做:
pointerOfRowIntf = root.findall(".//{http://www.cisco.com/nxos:1.0:ip}ROW_intf")
print pointerOfRowIntf
这样就会打印出找到的所有5个节点:
[<Element '{http://www.cisco.com/nxos:1.0:ip}ROW_intf' at 0x20d4990>, <Element '{http://www.cisco.com/nxos:1.0:ip}ROW_intf' at 0x20d4bb0>, <Element '{http://www.cisco.com/nxos:1.0:ip}ROW_intf' at 0x20d4db0>, <Element '{http://www.cisco.com/nxos:1.0:ip}ROW_intf' at 0x20d4f90>, <Element '{http://www.cisco.com/nxos:1.0:ip}ROW_intf' at 0x20dc190>]
1
要去掉标签上的命名空间:
import re
def GetBareTag(tag): return re.sub(r'{.*?}', '', tag)
要找到第一个子元素:
def GetFirstChild(e): return e[0] if len(e) else None