用Python处理XML的简单方法是什么?

2024-04-28 04:36:13 发布

您现在位置:Python中文网/ 问答频道 /正文

考虑到recently asked question,我开始怀疑是否有一种在Python中处理XML文档的真正简单的方法。如果你愿意的话,可以用一种Python的方式。

如果我举一个例子,也许我可以解释得最好:假设以下是我从http请求到http://www.google.com/ig/api?weather=94043的响应,我认为这是web服务中使用XML的一个很好的例子

<xml_api_reply version="1">
  <weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0" >
    <forecast_information>
      <city data="Mountain View, CA"/>
      <postal_code data="94043"/>
      <latitude_e6 data=""/>
      <longitude_e6 data=""/>
      <forecast_date data="2010-06-23"/>
      <current_date_time data="2010-06-24 00:02:54 +0000"/>
      <unit_system data="US"/>
    </forecast_information>
    <current_conditions>
      <condition data="Sunny"/>
      <temp_f data="68"/>
      <temp_c data="20"/>
      <humidity data="Humidity: 61%"/>
      <icon data="/ig/images/weather/sunny.gif"/>
      <wind_condition data="Wind: NW at 19 mph"/>
    </current_conditions>
    ...
    <forecast_conditions>
      <day_of_week data="Sat"/>
      <low data="59"/>
      <high data="75"/>
      <icon data="/ig/images/weather/partly_cloudy.gif"/>
      <condition data="Partly Cloudy"/>
    </forecast_conditions>
  </weather>
</xml_api_reply>

在加载/解析这样的文档之后,我希望能够简单地访问这些信息

>>> xml['xml_api_reply']['weather']['forecast_information']['city'].data
'Mountain View, CA'

或者

>>> xml.xml_api_reply.weather.current_conditions.temp_f['data']
'68'

从我目前看到的情况来看,似乎ElementTree最接近我的梦想。但事实并非如此,在使用XML时仍有一些麻烦要做。噢,我想的并不是那么复杂——可能只是解析器上的一层薄薄的表面——但是它可以减少处理XML的烦恼。有这样的魔力吗?(如果不是-为什么?)

注意,我已经尝试过BeautifulSoup,虽然我喜欢它的方法,但它确实存在空<element/>s的问题-请参见下面的注释中的示例。


Tags: 方法文档apidatainformationxmlcurrentcondition
3条回答

你想要薄饰板吗?这很容易烹调。请尝试以下简单的ElementTree包装作为开始:

# geetree.py
import xml.etree.ElementTree as ET

class GeeElem(object):
    """Wrapper around an ElementTree element. a['foo'] gets the
       attribute foo, a.foo gets the first subelement foo."""
    def __init__(self, elem):
        self.etElem = elem

    def __getitem__(self, name):
        res = self._getattr(name)
        if res is None:
            raise AttributeError, "No attribute named '%s'" % name
        return res

    def __getattr__(self, name):
        res = self._getelem(name)
        if res is None:
            raise IndexError, "No element named '%s'" % name
        return res

    def _getelem(self, name):
        res = self.etElem.find(name)
        if res is None:
            return None
        return GeeElem(res)

    def _getattr(self, name):
        return self.etElem.get(name)

class GeeTree(object):
    "Wrapper around an ElementTree."
    def __init__(self, fname):
        self.doc = ET.parse(fname)

    def __getattr__(self, name):
        if self.doc.getroot().tag != name:
            raise IndexError, "No element named '%s'" % name
        return GeeElem(self.doc.getroot())

    def getroot(self):
        return self.doc.getroot()

你这样调用它:

>>> import geetree
>>> t = geetree.GeeTree('foo.xml')
>>> t.xml_api_reply.weather.forecast_information.city['data']
'Mountain View, CA'
>>> t.xml_api_reply.weather.current_conditions.temp_f['data']
'68'

已经提到lxml。您还可以查看lxml.objectify以获得一些真正简单的操作。

>>> from lxml import objectify
>>> tree = objectify.fromstring(your_xml)
>>> tree.weather.attrib["module_id"]
'0'
>>> tree.weather.forecast_information.city.attrib["data"]
'Mountain View, CA'
>>> tree.weather.forecast_information.postal_code.attrib["data"]
'94043'

我强烈建议使用lxml.etree和xpath来解析和分析数据。这是一个完整的例子。为了便于阅读,我截断了xml。

import lxml.etree

s = """<?xml version="1.0" encoding="utf-8"?>
<xml_api_reply version="1">
  <weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0" >
    <forecast_information>
      <city data="Mountain View, CA"/> <forecast_date data="2010-06-23"/>
    </forecast_information>
    <forecast_conditions>
      <day_of_week data="Sat"/>
      <low data="59"/>
      <high data="75"/>
      <icon data="/ig/images/weather/partly_cloudy.gif"/>
      <condition data="Partly Cloudy"/>
    </forecast_conditions>
  </weather>
</xml_api_reply>"""

tree = lxml.etree.fromstring(s)
for weather in tree.xpath('/xml_api_reply/weather'):
    print weather.find('forecast_information/city/@data')[0]
    print weather.find('forecast_information/forecast_date/@data')[0]
    print weather.find('forecast_conditions/low/@data')[0]
    print weather.find('forecast_conditions/high/@data')[0]

相关问题 更多 >