使用lxml获取复杂元素的属性

时间:2011-11-17 02:54:06

标签: python lxml elementtree

我有一个简单的文件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,

现在,我想获得单位内部的属性,我尝试了很多不同的方式,但我失败了。大部分时间的错误是:

    '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>

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

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

希望它有所帮助。

相关问题