【问题标题】:Parse xml with lxml - extract element value使用 lxml 解析 xml - 提取元素值
【发布时间】:2012-09-21 08:15:27
【问题描述】:

假设我们有一个结构如下的 XML 文件。

<?xml version="1.0" ?> 
<searchRetrieveResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/zing/srw/ http://www.loc.gov/standards/sru/sru1-1archive/xml-files/srw-types.xsd" xmlns="http://www.loc.gov/zing/srw/">
  <records xmlns:ns1="http://www.loc.gov/zing/srw/">
    <record>
      <recordData>
        <record xmlns="">
          <datafield tag="000">
            <subfield code="a">123</subfield>
            <subfield code="b">456</subfield>
          </datafield>
          <datafield tag="001">
            <subfield code="a">789</subfield>
            <subfield code="b">987</subfield>
          </datafield>
        </record>
      </recordData>
    </record>
    <record>
      <recordData>
        <record xmlns="">
          <datafield tag="000">
            <subfield code="a">123</subfield>
            <subfield code="b">456</subfield>
          </datafield>
          <datafield tag="001">
            <subfield code="a">789</subfield>
            <subfield code="b">987</subfield>
          </datafield>
        </record>
      </recordData>
    </record>
  </records>
</searchRetrieveResponse>

我需要解析出来:

  • “子字段”的内容(例如上例中的 123)和
  • 属性值(例如 000 或 001)

我想知道如何使用 lxml 和 XPath 来做到这一点。下面粘贴的是我的初始代码,我请人解释一下,如何解析出值。

import urllib, urllib2
from lxml import etree    

url = "https://dl.dropbox.com/u/540963/short_test.xml"
fp = urllib2.urlopen(url)
doc = etree.parse(fp)
fp.close()

ns = {'xsi':'http://www.loc.gov/zing/srw/'}

for record in doc.xpath('//xsi:record', namespaces=ns):
    print record.xpath("xsi:recordData/record/datafield[@tag='000']", namespaces=ns)

【问题讨论】:

  • 您正在为命名空间http://www.loc.gov/zing/srw/ 使用前缀xsi - 这是有效的,但通常xsi 用作标准命名空间http://www.w3.org/2001/XMLSchema-instance 的前缀。

标签: python xml xpath lxml


【解决方案1】:

我会在您的 XPath 中更直接:直接找到您想要的元素,在本例中为 datafield

>>> for df in doc.xpath('//datafield'):
        # Iterate over attributes of datafield
        for attrib_name in df.attrib:
                print '@' + attrib_name + '=' + df.attrib[attrib_name]

        # subfield is a child of datafield, and iterate
        subfields = df.getchildren()
        for subfield in subfields:
                print 'subfield=' + subfield.text

另外,lxml 似乎让您忽略命名空间,可能是因为您的示例只使用一个命名空间?

【讨论】:

  • 是的,我只有一个命名空间。
【解决方案2】:

尝试以下工作代码:

import urllib2
from lxml import etree

url = "https://dl.dropbox.com/u/540963/short_test.xml"
fp = urllib2.urlopen(url)
doc = etree.parse(fp)
fp.close()

for record in doc.xpath('//datafield'):
    print record.xpath("./@tag")[0]
    for x in record.xpath("./subfield/text()"):
        print "\t", x

【讨论】:

    【解决方案3】:

    我会选择的

    for df in doc.xpath('//datafield'):
        print df.attrib
        for sf in df.getchildren():
            print sf.text
    

    另外你不需要urllib,你可以直接用HTTP解析XML

    url = "http://dl.dropbox.com/u/540963/short_test.xml"  #doesn't work with https though
    doc = etree.parse(url)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-20
      • 2015-09-19
      • 2012-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多