【问题标题】:LXML, how to get multiple set of attributes to listsLXML,如何获取列表的多组属性
【发布时间】:2011-12-30 10:05:30
【问题描述】:

我有类似这样的问题:

How do I select multiple sets of attributes within an XML document using XPath?

我的 XML 数据如下所示:

<?xml version="1.0" encoding="utf-8"?>
<Basic>
    <Segment>
        <Sample value="12" data2="25" data3="23"/>
        <Sample value="13" data2="0" data3="323"/>
        <Sample value="14" data2="2" data3="3"/>
    </Segment>
</Basic>

将这些datax 值添加到列表中的最简单的python 方法是什么。

例如:data2 = ['25','0','2']

【问题讨论】:

    标签: python xml lxml


    【解决方案1】:

    使用 xpath:

    from lxml import etree
    from collections import defaultdict
    from pprint import pprint
    
    doc="""<?xml version="1.0" encoding="utf-8"?>
    <Basic>
        <Segment>
            <Sample value="12" data2="25" data3="23"/>
            <Sample value="13" data2="0" data3="323"/>
            <Sample value="14" data2="2" data3="3"/>
        </Segment>
    </Basic>
    """
    el = etree.fromstring(doc)
    data2 = el.xpath('//@data2')
    dataX = el.xpath('//@*[starts-with(name(), "data")]')
    print data2
    print dataX
    
    # With iteration over Sample elements, like in J.F. Sebastian answer, but with XPath
    d = defaultdict(list)
    for sample in el.xpath('//Sample'):
        for attr_name, attr_value in sample.items():
            d[attr_name].append(attr_value)
    
    pprint(dict(d))
    

    输出:

    ['25', '0', '2']
    ['25', '23', '0', '323', '2', '3']
    {'data2': ['25', '0', '2'],
     'data3': ['23', '323', '3'],
     'value': ['12', '13', '14']}
    

    【讨论】:

    • 你可以用el.iter('Sample')代替el.xpath('//Sample')
    • @J.F.Sebastian,你是对的,但是通过使用 xpath,你可以在一行中添加额外的逻辑,例如el.xpath('//Sample[@value &lt; 14]') 仅选择值小于 14 的元素等。
    • 最终使用了这个。实际上是for循环部分。这对我有好处,因为 xml-file 并不总是具有所有属性。另一个答案也可以,但我觉得这更简单。
    【解决方案2】:

    获取属性值最简单的方法是使用etree.Element.get('attr_name'):

    from lxml import etree
    
    s = '''<?xml version="1.0" encoding="utf-8"?>
    <Basic>
        <Segment>
            <Sample value="12" data2="25" data3="23"/>
            <Sample value="13" data2="0" data3="323"/>
            <Sample value="14" data2="2" data3="3"/>
        </Segment>
    </Basic>'''
    
    # ❗️for python2
    # tree = etree.fromstring(s)
    
    # ❗️for python3
    tree = etree.fromstring(s.encode("utf-8"))
    
    samples = tree.xpath('//Sample')
    
    print([sample.get('data2') for sample in samples])
    >>> ['25', '0', '2']
    

    【讨论】:

    • 我真的很想使用 get 但我无法让它与命名空间属性一起使用。对于此示例,它将是:xml:data2="25"。使用 xpath,我可以得到很多或更少的结果。有什么想法可以使用命名空间吗?
    • @MisterT:您需要先使用ns = tree.getroot().nsmap 获取命名空间映射,然后将命名空间传递给您的xpath 调用tree.xpath(xpath_expression, namespaces=ns)
    • 感谢这仍然将我推向了正确的方向。 stackoverflow.com/questions/31063541/…。我看到的唯一缺点是我必须遍历每个孩子,而不仅仅是父母......
    【解决方案3】:

    使用来自 stdlib 的cElementTree

    import sys
    from collections import defaultdict
    from xml.etree import cElementTree as etree
    
    d = defaultdict(list)
    for ev, el in etree.iterparse(sys.stdin):
        if el.tag == 'Sample':
           for name in "value data2 data3".split():
               d[name].append(el.get(name))
    print(d)
    

    Output

    {'data2': ['25', '0', '2'],
     'data3': ['23', '323', '3'],
     'value': ['12', '13', '14']}
    

    如果您使用lxml.etree,那么您可以:etree.iterparse(file, tag='Sample') 选择iterparse() 中的Sample 元素,即在这种情况下您可以删除if el.tag == 'Sample' 条件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-27
      • 2010-10-18
      • 1970-01-01
      • 2018-07-17
      • 2020-02-29
      • 1970-01-01
      • 2014-01-18
      相关资源
      最近更新 更多