使用 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