【问题标题】:Get attribute of complex element using lxml使用lxml获取复杂元素的属性
【发布时间】:2011-11-17 02:54:06
【问题描述】:

我有一个简单的 XML 文件,如下所示:

    <brandName type="http://example.com/codes/bmw#" abbrev="BMW" value="BMW" />BMW</brandName>
      <maxspeed>
        <value>250</value>
        <unit type="http://example.com/codes/units#" value="miles per hour" abbrev="mph" />
      </maxspeed>

我想使用 lxml 解析它并获取它的值: 使用brandName,它只需要:

    'brand_name'  : m.findtext(NS+'brandName')

如果我想进入它的 abbrev 属性。

    'brand_name'  : m.findtext(NS+'brandName').attrib['abbrev']

使用 maxspeed,我可以通过以下方式获得 maxspeed 的值:

    'maxspeed_value'                  : m.findtext(NS+'maxspeed/value'),

或:

    'maxspeed_value'                  : m.find(NS+'maxspeed/value').text,

现在,我想获取 unit inside 的属性,我尝试了很多不同的方法,但都失败了。大多数时候的错误是:

    'NoneType' object has no attribute 'attrib'

我尝试了以下几种方法,但都失败了:

    'maxspeed_unit'                  : m.find(NS+'maxspeed/value').attrib['abbrev'],
    'maxspeed_unit'                  : (m.find(NS+'maxspeed/value'))get('abbrev'),

您能否给我一些提示,为什么它不起作用? 非常感谢!

更新 XML:

    <Car xmlns="http://example.com/vocab/xml/cars#">
     <dateStarted>2011-02-05</dateStarted>
     <dateSold>2011-02-13</dateSold>
    <name type="http://example.com/codes/bmw#" abbrev="X6" value="BMW X6" >BMW X6</name>
    <brandName type="http://example.com/codes/bmw#" abbrev="BMW" value="BMW" />BMW</brandName>
      <maxspeed>
        <value>250</value>
        <unit type="http://example.com/codes/units#" value="miles per hour" abbrev="mph" />
      </maxspeed>
      <route type="http://example.com/codes/routes#" abbrev="HW" value="Highway" >Highway</route>
      <power>
        <value>180</value>
        <unit type="http://example.com/codes/units#" value="powerhorse" abbrev="ph" />
      </power>
      <frequency type="http://example.com/codes/frequency#" value="daily" >Daily</frequency>  
    </Car>

【问题讨论】:

  • 我刚刚尝试了另一个,但没有成功:'maxspeed_unit' : m.find('.//maxspeed/unit').get('abbrev') 因为我从这里看到:sites.google.com/site/bmaupinwiki/home/programming/python/… 我认为当前元素是maxspeed/value,所以在里面找不到maxspeed/unit。但是我不知道如何让它回到一个级别,所以我尝试了.//,但它没有工作。

标签: python lxml elementtree


【解决方案1】:

lxml 元素上的 .find 方法只会搜索该元素的直接子子元素。所以例如在这个xml中:

<root>
    <brandName type="http://example.com/codes/bmw#" abbrev="BMW" value="BMW">BMW</brandName>
    <maxspeed>
        <value>250</value>
        <unit type="http://example.com/codes/units#" value="miles per hour" abbrev="mph" />
    </maxspeed>
</root>

您可以使用根元素的.find 方法来定位brandname 元素或maxspeed 元素,但搜索不会在这些内部元素内部遍历。

所以你可以做这样的事情:

root.find('maxspeed').find('unit') #returns the unit Element

从此返回的元素中,您可以访问属性。

如果您想搜索 XML 文档中的所有元素,可以使用 .iter() 方法。所以对于前面的例子,你可以说:

for element in root.iter(tag='unit'):
    print element #This would print all the unit elements in the document.

编辑:这是一个使用您提供的 xml 的小型全功能示例:

import lxml.etree
from StringIO import StringIO

def ns_join(element, tag, namespace=None):
    '''Joins the namespace and tag together, and
    returns the fully qualified name.
    @param element - The lxml.etree._Element you're searching
    @param tag - The tag you're joining
    @param namespace - (optional) The Namespace shortname default is None'''

    return '{%s}%s' % (element.nsmap[namespace], tag)

def parse_car(element):
    '''Parse a car element, This will return a dictionary containing
    brand_name, maxspeed_value, and maxspeed_unit'''

    maxspeed = element.find(ns_join(element,'maxspeed'))
    return { 
        'brand_name' : element.findtext(ns_join(element,'brandName')), 
        'maxspeed_value' : maxspeed.findtext(ns_join(maxspeed,'value')), 
        'maxspeed_unit' : maxspeed.find(ns_join(maxspeed, 'unit')).attrib['abbrev']
        }

#Create the StringIO object to feed to the parser.
XML = StringIO('''
<Reports>
    <Car xmlns="http://example.com/vocab/xml/cars#">
        <dateStarted>2011-02-05</dateStarted>
        <dateSold>2011-02-13</dateSold>
        <name type="http://example.com/codes/bmw#" abbrev="X6" value="BMW X6" >BMW X6</name>
        <brandName type="http://example.com/codes/bmw#" abbrev="BMW" value="BMW" >BMW</brandName>
        <maxspeed>
            <value>250</value>
            <unit type="http://example.com/codes/units#" value="miles per hour" abbrev="mph" />
        </maxspeed>
        <route type="http://example.com/codes/routes#" abbrev="HW" value="Highway" >Highway</route>
        <power>
            <value>180</value>
            <unit type="http://example.com/codes/units#" value="powerhorse" abbrev="ph" />
        </power>
        <frequency type="http://example.com/codes/frequency#" value="daily" >Daily</frequency>  
    </Car>
</Reports>
''')

#Get the root element object of the xml
car_root_element = lxml.etree.parse(XML).getroot()

# For each 'Car' tag in the root element,
# we want to parse it and save the list as cars
cars = [ parse_car(element) 
    for element in car_root_element.iter() if element.tag.endswith('Car')]

print cars

希望对你有帮助。

【讨论】:

  • 我看到这个错误:'NoneType' 对象没有属性 'find' 代码:car.append({ 'brand_name' : m.findtext(NS+'brandName'), 'maxspeed' : m .findtext(NS+'dose/value') 'maxspeed_value': m.find('dose').find('value').attrib['abbrev'], }) 我可以只在 1 行代码上做吗?
  • 如果您要搜索的元素不存在,.find() 将返回 None。在您提供的示例中,您确定存在“剂量”元素吗?
  • 对不起,正确的代码是:car.append({ 'brand_name' : m.findtext(NS+'brandName'), 'maxspeed' : m.findtext(NS+'maxspeed/value') ' maxspeed_value': m.find('maxspeed').find('value').attrib['abbrev'], )
  • 'maxspeed_unit': m.find('maxspeed').find('unit').attrib['abbrev'],没用。
  • ''maxspeed_unit': ((m.find(''maxspeed')).find('unit')).attrib['value'],也没有用!
【解决方案2】:
import lxml.etree as ET
content='''
<Car xmlns="http://example.com/vocab/xml/cars#">
 <brandName type="http://example.com/codes/bmw#" abbrev="BMW" value="BMW" >BMW</brandName>
   <maxspeed>
     <value>250</value>
     <unit type="http://example.com/codes/units#" value="miles per hour" abbrev="mph" />
   </maxspeed>
 </Car>
'''

doc=ET.fromstring(content)
NS = 'http://example.com/vocab/xml/cars#'
# print(ET.tostring(doc,pretty_print=True))
for x in doc.xpath('//ns:maxspeed/ns:unit/@abbrev',namespaces={'ns': NS}):
    print(x)

产量

mph

【讨论】:

  • 我改成:'maxspeed_unit' : m.xpath('//ns:maxspeed/ns:unit/@abbrev',namespaces={'ns': NS}) ,没有这个错误,但是brand_name有另一个错误:'brand_name':m.findtext(NS +'brandName'),太奇怪了。我不知道为什么。有客人吗?
  • 错误是一样的:'NoneType'对象没有属性'attrib'
  • 我重启没有像上面这样的错误,但它有这个错误:_ElementInterface instance has no attribute 'xpath'
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-16
  • 1970-01-01
相关资源
最近更新 更多