使用BeautifulSoup将XML解析为字典

时间:2014-11-11 18:52:59

标签: xml python-2.7 beautifulsoup

我有一段看起来像这样的XML:

 <ns:Vehicle>
  <ns:Model>AVALON</ns:Model>
  <ns:ModelYear>1998</ns:ModelYear>
  <ns:MakeString>TY</ns:MakeString>
  <ns:VehicleID>VIN NUMBER GOES HERE</ns:VehicleID>
 </ns:Vehicle>

我有以下代码将车辆元素变成字典:

xml_file = open('6046179.xml')
soup = BeautifulSoup(xml_file)

# Vehicle elements
el_model = soup.find('ns:model').text
el_model_year = soup.find('ns:modelyear').text
el_make_string = soup.find('ns:makestring').text
el_vehicle_id = soup.find('ns:vehicleid').text

vehicle = {'model': '{}'.format(el_model),
           'model_year': '{}'.format(el_model_year),
           'make_string': '{}'.format(el_make_string),
           'vehicle_id': '{}'.format(el_vehicle_id)}

print vehicle

我只是想知道是否有更好的方法来做到这一点,我不介意浏览XML中的其他元素并单独定义它们,我只是想知道是否有更干净的这样做的方法。

3 个答案:

答案 0 :(得分:2)

可能会更清洁,但基本上没有什么不同:

tags = ['model', 'modelyear', 'makestring', 'vehicleid']
vehicle = {}
for tag in tags:
    vehicle[tag] = '{}'.format(soup.find('ns:' + tag).text)

还有xmltodict可能值得一看。

答案 1 :(得分:1)

BeautifulSoup并不适用于XML - 它非常适合凌乱的HTML,这会破坏正确的解析器。

你最好使用etree接口(通过,也许是非常快的lxml),无论如何,IIRC是BS默认使用的。然后你得到root元素并用几行代码迭代它的所有子元素,例如:

#!/usr/bin/env python

import xml.etree.ElementTree as ET
import re

# Note the dummy namespace that must / should have been there...
xml = '''
 <ns:Vehicle xmlns:ns="http://foo.bar">
  <ns:Model>AVALON</ns:Model>
  <ns:ModelYear>1998</ns:ModelYear>
  <ns:MakeString>TY</ns:MakeString>
  <ns:VehicleID>VIN NUMBER GOES HERE</ns:VehicleID>
 </ns:Vehicle>'''

tree = ET.fromstring(xml)
vehicle = {re.sub(r'{.*}', '', node.tag): node.text for node in tree}

答案 2 :(得分:1)

如果你想要{em> all <ns:Vehicle>元素中的子节点,你不需要明确指定它们 - 只需遍历所有子元素并将它们放入字典。

from bs4 import BeautifulSoup

soup = BeautifulSoup('''
 <ns:Vehicle>
  <ns:Model>AVALON</ns:Model>
  <ns:ModelYear>1998</ns:ModelYear>
  <ns:MakeString>TY</ns:MakeString>
  <ns:VehicleID>VIN NUMBER GOES HERE</ns:VehicleID>
 </ns:Vehicle>
 ''')

# loop if you have multiple vehicles
# Note that BS normalizes all tag names to lowercase -> we use 'ns:vehicle' rather 'ns:Vehicle'
for el_vehicle in soup.find_all('ns:vehicle'): 
    vehicle = {child.name: child.text for child in el_vehicle.findChildren()}
    # stick `vehicle` in a list or do some other processing

这并不完全匹配您的输出,因为它不会从camelcase转换为以下划线分隔的名称(例如ModelYearmodel_year),并且它也没有&#39;从名称名称中删除名称空间。如果您需要,那么在child.name周围包含一个包装器以便相应地更改名称就不会太困难。