【问题标题】:How to parse xml elements to python from a very large xml file?如何从非常大的 xml 文件中将 xml 元素解析为 python?
【发布时间】:2019-07-11 14:39:06
【问题描述】:

我目前正在开发一个程序,该程序有 20 个左右的脚本,可以从一个使用子进程库调用这些脚本的 python 文件中调用。每个脚本都有 3 个参数,用户当前必须使用 argparse 在其中输入:ip 地址、用户名和密码。这些脚本自动测试网络设备等。

现在,我不想让用户在命令行上输入这些参数,而是想从我的公司生成的包含大约 5,000 行代码的 XML 文件中提取这些值。我可以提取所需信息的最佳方法是什么,以便用户不必手动输入参数?

我进行了一些研究,但遗憾的是我无法理解执行此操作的最佳方法。以下是 xml 文件的示例摘录:

<sheet>
        <name>7_managementHosts</name>
        <data>
            <name>MgtHosts</name>
            <key>
                <name>Rack U-Location</name>
                <value>U30</value>
                <value>U29</value>
                <value>U28</value>
            </key>
            <key>
                <name>Default Component Name</name>
                <value>sms01</value>
                <value>sms02</value>
                <value>sms03</value>
            </key>
            <key>
                <name>DNS hostname (FQDN)</name>
                <value>sms01.de1000.local</value>
                <value>sms02.de1000.local</value>
                <value>sms03.de1000.local</value>
            </key>
            <key>
                <name>DNS suffix for management interface</name>
                <value>de1000.local</value>
                <value>de1000.local</value>
                <value>de1000.local</value>
            </key>
            <key>
                <name>Keyboard layout</name>
                <value>US Default</value>
                <value>US Default</value>
                <value>US Default</value>
            </key>
            <key>
                <name>root user password</name>
                <value>myPassword</value>
                <value>myPassword</value>
                <value>myPassword</value>
            </key>

这是一个非常长的 XML 文件,但树是这样的,我真的不知道解决这个问题的最佳方法。感谢您的帮助!

【问题讨论】:

  • Python 为 XML 文件的基本输入/输出提供了 xml module - 这将帮助您以您的程序可以操作的方式读取 XML 文件。或者,您可以查看BeautifulSoup,这是一个 HTML/XML 解析库,它可能更易于使用,具体取决于您要对该文件执行的操作。

标签: python xml xml-parsing


【解决方案1】:

使用 python standard XML lib (假设您想在 'key' 元素下收集数据)

import xml.etree.ElementTree as ET
import pprint

xml = '''<sheet>
        <name>7_managementHosts</name>
        <data>
            <name>MgtHosts</name>
            <key>
                <name>Rack U-Location</name>
                <value>U30</value>
                <value>U29</value>
                <value>U28</value>
            </key>
            <key>
                <name>Default Component Name</name>
                <value>sms01</value>
                <value>sms02</value>
                <value>sms03</value>
            </key>
            <key>
                <name>DNS hostname (FQDN)</name>
                <value>sms01.de1000.local</value>
                <value>sms02.de1000.local</value>
                <value>sms03.de1000.local</value>
            </key>
            <key>
                <name>DNS suffix for management interface</name>
                <value>de1000.local</value>
                <value>de1000.local</value>
                <value>de1000.local</value>
            </key>
            <key>
                <name>Keyboard layout</name>
                <value>US Default</value>
                <value>US Default</value>
                <value>US Default</value>
            </key>
            <key>
                <name>root user password</name>
                <value>myPassword</value>
                <value>myPassword</value>
                <value>myPassword</value>
            </key>
        </data>
    </sheet>'''

data = {}
root = ET.fromstring(xml)
keys = root.findall('.//data/key')
for key in keys:
    data[key.find('name').text] = [v.text for v in  key.findall('value')]
pprint.pprint(data)

输出

{'DNS hostname (FQDN)': ['sms01.de1000.local',
                         'sms02.de1000.local',
                         'sms03.de1000.local'],
 'DNS suffix for management interface': ['de1000.local',
                                         'de1000.local',
                                         'de1000.local'],
 'Default Component Name': ['sms01', 'sms02', 'sms03'],
 'Keyboard layout': ['US Default', 'US Default', 'US Default'],
 'Rack U-Location': ['U30', 'U29', 'U28'],
 'root user password': ['myPassword', 'myPassword', 'myPassword']}

【讨论】:

  • 顺便说一句 - Andrej Kesely 的解决方案需要安装 2 个库:BeautifulSoup & lxml
  • 谢谢,但您的解决方案是给我一个 Traceback。对于您创建的 xml 变量,我输入了我的文件名 xml = 'SmartCID_XML.xml' 。也许这就是问题所在?
  • @SaturnsBelt 是的。这就是问题。以我的示例为例,如果这对您有用,请将root = ET.fromstring(xml)root = ET.parse('my_data.xml') 切换行
  • 它有效。我刚刚给了你一个检查表,这正是我所需要的。我需要为每个设备使用 IP 地址。这本词典是什么格式的?看着它是压倒性的。是 data = {name : [keys]} 吗?
  • @SaturnsBelt 我不确定我是否理解您的问题。你能试着改写一下吗?
【解决方案2】:

BeautifulSoup 为例,只是为了让您开始使用该模块:

data = '''
<sheet>
        <name>7_managementHosts</name>
        <data>
            <name>MgtHosts</name>
            <key>
                <name>Rack U-Location</name>
                <value>U30</value>
                <value>U29</value>
                <value>U28</value>
            </key>
            <key>
                <name>Default Component Name</name>
                <value>sms01</value>
                <value>sms02</value>
                <value>sms03</value>
            </key>
            <key>
                <name>DNS hostname (FQDN)</name>
                <value>sms01.de1000.local</value>
                <value>sms02.de1000.local</value>
                <value>sms03.de1000.local</value>
            </key>
            <key>
                <name>DNS suffix for management interface</name>
                <value>de1000.local</value>
                <value>de1000.local</value>
                <value>de1000.local</value>
            </key>
            <key>
                <name>Keyboard layout</name>
                <value>US Default</value>
                <value>US Default</value>
                <value>US Default</value>
            </key>
            <key>
                <name>root user password</name>
                <value>myPassword</value>
                <value>myPassword</value>
                <value>myPassword</value>
            </key>
 '''

from bs4 import BeautifulSoup

data = BeautifulSoup(data, 'lxml')

parsed = [[v.text for v in key.select('name, value')] for key in data.select('key')]

# just for pretty printing, all the data are in `parsed` variable
from textwrap import shorten
for row_num, row in enumerate(zip(*parsed), 0):
    if row_num == 0:
        print(''.join('{: ^25}'.format(shorten(d, 25)) for d in ['Row Number'] + list(row)))
    else:
        print(''.join('{: ^25}'.format(shorten(d, 25)) for d in [str(row_num)] + list(row)))

打印:

   Row Number             Rack U-Location      Default Component Name     DNS hostname (FQDN)     DNS suffix for [...]        Keyboard layout        root user password    
        1                       U30                     sms01             sms01.de1000.local          de1000.local              US Default               myPassword        
        2                       U29                     sms02             sms02.de1000.local          de1000.local              US Default               myPassword        
        3                       U28                     sms03             sms03.de1000.local          de1000.local              US Default               myPassword        

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-28
    • 1970-01-01
    • 1970-01-01
    • 2013-03-24
    • 2015-08-26
    • 1970-01-01
    相关资源
    最近更新 更多