使用 Python 解析 XML 格式的网络设备清单
Parsing Network Device Inventory in XML Format with Python
我是 Python 的新手 - 正在尝试解析包含交换机和路由器清单的 xml 文件。
我已经尝试通过导入 ET 并使用以下代码来获取 xml 文件中的第一行或两行库存:
(我已经阅读了该站点上解析 xml 文件的其他解决方案,并尝试了其中的一些,即使使用 BeautifulSoup,但我的 xml 文件的结构并不好.).
我可以用 Python 识别根和根的子节点,但是,我遇到的问题是向下钻取并调用“table_data”下包含的实际数据。下面是 xml 文件的一个片段,文件中还有大约 20 个设备。
在 for 循环中我试过 'field name',我也试过 'field' 和 'name' 但没有结果。
当然,此时调用 'for loop' 内的其他标签是行不通的。
如果您能指出正确的方向,我将不胜感激。
import xml.etree.ElementTree as ET
tree = ET.parse('ios_inventory.xml')
root = tree.getroot()
for f in root.findall('field'):
att=f.attrib
n=att.get('name')
'ios_inventory.xml'
的内容
<?xml version="1.0"?>
<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<database name="IOS_INVENTORY">
<table_structure name="Cisco_IOS_Inventory">
<field Field="Hostname" Type="varchar(100)" Null="YES" Key="" Extra="" Comment="" />
<field Field="Local_IPs" Type="varchar(5000)" Null="YES" Key="" Extra="" Comment="" />
<field Field="Local_SVI_IPs" Type="varchar(5000)" Null="YES" Key="" Extra="" Comment="" />
<field Field="IOS_Image" Type="varchar(200)" Null="YES" Key="" Extra="" Comment="" />
<field Field="IOSVersion" Type="varchar(200)" Null="YES" Key="" Extra="" Comment="" />
<field Field="Flash" Type="varchar(200)" Null="YES" Key="" Extra="" Comment="" />
<field Field="SerialNo" Type="varchar(2000)" Null="YES" Key="" Extra="" Comment="" />
<options Name="Cisco_IOS_Inventory" Engine="InnoDB" Version="10" Row_format="Compact"
Rows="37" Avg_row_length="442" Data_length="16384" Max_data_length="0" Index_length="0"
Data_free="5242880" Create_time="2017-05-31 04:23:01" Collation="latin1_swedish_ci"
Create_options="" Comment="" />`
</table_structure>
<table_data name="Cisco_IOS_Inventory">
<row>
<field name="Hostname">SW2
</field>
<field name="Local_IPs"></field>
<field name="Local_SVI_IPs">10.100.x.x</field>
<field name="IOS_Image">CAT3K_CAA-UNIVERSALK9-M</field>
<field name="IOSVersion">03.06.10E RELEASE SOFTWARE (fc2)</field>
<field name="Flash">1621966848 bytes total</field>
<field name="SerialNo">xxxxxxxxxxxxx</field>
</row>
<row>
<field name="Hostname">SW3
</field>
<field name="Local_IPs"></field>
<field name="Local_SVI_IPs">10.100.x.x</field>
<field name="IOS_Image">CAT3K_CAA-UNIVERSALK9-M</field>
<field name="IOSVersion">03.06.10E RELEASE SOFTWARE (fc2)</field>
<field name="Flash">1621966848 bytes total</field>
<field name="SerialNo">xxxxxxxxxxxxx</field>
</row>
<row>
<field name="Hostname">RTR_2</field>
<field name="Local_IPs">10.100.x.x | 10.253.x.x</field>
<field name="Local_SVI_IPs"></field>
<field name="IOS_Image">X86_64_LINUX_IOSD-UNIVERSALK9-M</field>
<field name="IOSVersion">16.4.2, RELEASE SOFTWARE (fc1)</field>
<field name="Flash">6741659648 bytes total</field>
<field name="SerialNo">XXXXXXXXX</field>
</row>
谢谢杰克。我在底部粘贴了简短的 xml 示例。想要获得如下所示的输出 - 具有相应的值。
请注意:Local_SVI_IPs 在 xml 文件中可以有多个 IP 地址。
hostname:
Local_SVI_IPs:
IOS_Image:
IOSVersion:
Flash:
SerialNo:
<field name="Hostname">SW2</field>
<field name="Local_IPs"></field>
<field name="Local_SVI_IPs">10.100.x.x</field>
<field name="IOS_Image">CAT3K_CAA-UNIVERSALK9-M</field>
<field name="IOSVersion">03.06.10E RELEASE SOFTWARE (fc2)</field>
<field name="Flash">1621966848 bytes total</field>
<field name="SerialNo">xxxxxxxxxxxxx</field>
</row>
在你的实际 xml 上试试这个;但是对于您提供的那个(请注意,问题中的 xml 仍然格式不正确):
from lxml import etree
hosts = """[your xml above, fixed]"""
doc = etree.XML(hosts)
rows = doc.xpath('//row')
for row in rows:
print('hostname: ',row.xpath('field[@name="Hostname"]/text()')[0].strip())
if len(row.xpath('field[@name="Local_SVI_IPs"]/text()'))>0:
print('Local_SVI_IPs: ',row.xpath('field[@name="Local_SVI_IPs"]/text()')[0].strip())
else:
print('Local_SVI_IPs: NA')
print('IOS_Image: ',row.xpath('field[@name="IOS_Image"]/text()')[0].strip())
print('IOSVersion: ',row.xpath('field[@name="IOSVersion"]/text()')[0].strip())
print('Flash: ',row.xpath('field[@name="Flash"]/text()')[0].strip())
print('SerialNo: ',row.xpath('field[@name="SerialNo"]/text()')[0].strip())
print('-------')
输出:
hostname: SW2
Local_SVI_IPs: 10.100.x.x
IOS_Image: CAT3K_CAA-UNIVERSALK9-M
IOSVersion: 03.06.10E RELEASE SOFTWARE (fc2)
Flash: 1621966848 bytes total
SerialNo: xxxxxxxxxxxxx
-------
hostname: SW3
Local_SVI_IPs: 10.100.x.x
IOS_Image: CAT3K_CAA-UNIVERSALK9-M
IOSVersion: 03.06.10E RELEASE SOFTWARE (fc2)
Flash: 1621966848 bytes total
SerialNo: xxxxxxxxxxxxx
-------
hostname: RTR_2
Local_SVI_IPs: NA
IOS_Image: X86_64_LINUX_IOSD-UNIVERSALK9-M
IOSVersion: 16.4.2, RELEASE SOFTWARE (fc1)
Flash: 6741659648 bytes total
SerialNo: XXXXXXXXX
我是 Python 的新手 - 正在尝试解析包含交换机和路由器清单的 xml 文件。 我已经尝试通过导入 ET 并使用以下代码来获取 xml 文件中的第一行或两行库存: (我已经阅读了该站点上解析 xml 文件的其他解决方案,并尝试了其中的一些,即使使用 BeautifulSoup,但我的 xml 文件的结构并不好.).
我可以用 Python 识别根和根的子节点,但是,我遇到的问题是向下钻取并调用“table_data”下包含的实际数据。下面是 xml 文件的一个片段,文件中还有大约 20 个设备。 在 for 循环中我试过 'field name',我也试过 'field' 和 'name' 但没有结果。 当然,此时调用 'for loop' 内的其他标签是行不通的。 如果您能指出正确的方向,我将不胜感激。
import xml.etree.ElementTree as ET
tree = ET.parse('ios_inventory.xml')
root = tree.getroot()
for f in root.findall('field'):
att=f.attrib
n=att.get('name')
'ios_inventory.xml'
的内容 <?xml version="1.0"?>
<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<database name="IOS_INVENTORY">
<table_structure name="Cisco_IOS_Inventory">
<field Field="Hostname" Type="varchar(100)" Null="YES" Key="" Extra="" Comment="" />
<field Field="Local_IPs" Type="varchar(5000)" Null="YES" Key="" Extra="" Comment="" />
<field Field="Local_SVI_IPs" Type="varchar(5000)" Null="YES" Key="" Extra="" Comment="" />
<field Field="IOS_Image" Type="varchar(200)" Null="YES" Key="" Extra="" Comment="" />
<field Field="IOSVersion" Type="varchar(200)" Null="YES" Key="" Extra="" Comment="" />
<field Field="Flash" Type="varchar(200)" Null="YES" Key="" Extra="" Comment="" />
<field Field="SerialNo" Type="varchar(2000)" Null="YES" Key="" Extra="" Comment="" />
<options Name="Cisco_IOS_Inventory" Engine="InnoDB" Version="10" Row_format="Compact"
Rows="37" Avg_row_length="442" Data_length="16384" Max_data_length="0" Index_length="0"
Data_free="5242880" Create_time="2017-05-31 04:23:01" Collation="latin1_swedish_ci"
Create_options="" Comment="" />`
</table_structure>
<table_data name="Cisco_IOS_Inventory">
<row>
<field name="Hostname">SW2
</field>
<field name="Local_IPs"></field>
<field name="Local_SVI_IPs">10.100.x.x</field>
<field name="IOS_Image">CAT3K_CAA-UNIVERSALK9-M</field>
<field name="IOSVersion">03.06.10E RELEASE SOFTWARE (fc2)</field>
<field name="Flash">1621966848 bytes total</field>
<field name="SerialNo">xxxxxxxxxxxxx</field>
</row>
<row>
<field name="Hostname">SW3
</field>
<field name="Local_IPs"></field>
<field name="Local_SVI_IPs">10.100.x.x</field>
<field name="IOS_Image">CAT3K_CAA-UNIVERSALK9-M</field>
<field name="IOSVersion">03.06.10E RELEASE SOFTWARE (fc2)</field>
<field name="Flash">1621966848 bytes total</field>
<field name="SerialNo">xxxxxxxxxxxxx</field>
</row>
<row>
<field name="Hostname">RTR_2</field>
<field name="Local_IPs">10.100.x.x | 10.253.x.x</field>
<field name="Local_SVI_IPs"></field>
<field name="IOS_Image">X86_64_LINUX_IOSD-UNIVERSALK9-M</field>
<field name="IOSVersion">16.4.2, RELEASE SOFTWARE (fc1)</field>
<field name="Flash">6741659648 bytes total</field>
<field name="SerialNo">XXXXXXXXX</field>
</row>
谢谢杰克。我在底部粘贴了简短的 xml 示例。想要获得如下所示的输出 - 具有相应的值。 请注意:Local_SVI_IPs 在 xml 文件中可以有多个 IP 地址。
hostname:
Local_SVI_IPs:
IOS_Image:
IOSVersion:
Flash:
SerialNo:
<field name="Hostname">SW2</field>
<field name="Local_IPs"></field>
<field name="Local_SVI_IPs">10.100.x.x</field>
<field name="IOS_Image">CAT3K_CAA-UNIVERSALK9-M</field>
<field name="IOSVersion">03.06.10E RELEASE SOFTWARE (fc2)</field>
<field name="Flash">1621966848 bytes total</field>
<field name="SerialNo">xxxxxxxxxxxxx</field>
</row>
在你的实际 xml 上试试这个;但是对于您提供的那个(请注意,问题中的 xml 仍然格式不正确):
from lxml import etree
hosts = """[your xml above, fixed]"""
doc = etree.XML(hosts)
rows = doc.xpath('//row')
for row in rows:
print('hostname: ',row.xpath('field[@name="Hostname"]/text()')[0].strip())
if len(row.xpath('field[@name="Local_SVI_IPs"]/text()'))>0:
print('Local_SVI_IPs: ',row.xpath('field[@name="Local_SVI_IPs"]/text()')[0].strip())
else:
print('Local_SVI_IPs: NA')
print('IOS_Image: ',row.xpath('field[@name="IOS_Image"]/text()')[0].strip())
print('IOSVersion: ',row.xpath('field[@name="IOSVersion"]/text()')[0].strip())
print('Flash: ',row.xpath('field[@name="Flash"]/text()')[0].strip())
print('SerialNo: ',row.xpath('field[@name="SerialNo"]/text()')[0].strip())
print('-------')
输出:
hostname: SW2
Local_SVI_IPs: 10.100.x.x
IOS_Image: CAT3K_CAA-UNIVERSALK9-M
IOSVersion: 03.06.10E RELEASE SOFTWARE (fc2)
Flash: 1621966848 bytes total
SerialNo: xxxxxxxxxxxxx
-------
hostname: SW3
Local_SVI_IPs: 10.100.x.x
IOS_Image: CAT3K_CAA-UNIVERSALK9-M
IOSVersion: 03.06.10E RELEASE SOFTWARE (fc2)
Flash: 1621966848 bytes total
SerialNo: xxxxxxxxxxxxx
-------
hostname: RTR_2
Local_SVI_IPs: NA
IOS_Image: X86_64_LINUX_IOSD-UNIVERSALK9-M
IOSVersion: 16.4.2, RELEASE SOFTWARE (fc1)
Flash: 6741659648 bytes total
SerialNo: XXXXXXXXX