使用lxml读取xml并比较元素

时间:2013-06-07 17:29:59

标签: python xml lxml

我已尝试在StackOverflow上搜索各种问题和答案,但无法找到适合我情况的解决方案,所以这是我的问题。

我有3个xml文件,我试图比较。我遇到的问题是一次抓取“Main”XML文件的各个部分并将信息保存在一起。例如,我想保留与1相关的信息,并能够使用脚本中的每个部分。

此XML文件可以在标记之间包含任意数量的字段,但我只需要5个特定字段。我是Python的新手,使用Python阅读文本文件非常新,任何帮助都将不胜感激。

xml的示例如下。

Main XML:
    <?xml version="1.0" encoding="ISO-8859-1" ?>
    <resultset table="foo_bar">
    <row>
        <field name="id">1</field>
        <field name="name">foo 1</field>
        <field name="item 1">bar 1</field>
        <field name="item 2">Accepted</field>
        <field name="item 3">Accepted</field>
    </row>
    <row>
        <field name="id">2</field>
        <field name="name">foo 2</field>
        <field name="item 1">bar 2</field>
        <field name="item 2">Declined</field>
        <field name="item 3">Accepted</field>
    </row>
    <row>
        <field name="id">3</field>
        <field name="name">foo 3</field>
        <field name="item 1">bar 3</field>
        <field name="item 2">Accepted</field>
        <field name="item 3">Declined</field>
    </row>
    .....Continues
    </resultset>

我尝试过针对类似问题的各种答案,但到目前为止都没有成功。

编辑我尝试了多种方法,我将不得不深入研究各种.py脚本来查找所有这些内容。以下是基于here

问题的最新信息
from lxml import etree as ET

def filter_by_itemid(doc, idlist):
    rowset = doc.xpath("//row")
    for elem in rowset.getchildren():
        if elem.get("*") not in idlist:
            rowset.remove(elem)
    return doc

doc = ET.parse("my.xml")
filter_by_itemid(doc, ['id', 'name', 'item 1', 'item 2', 'item 3'])

print(ET.tostring(doc))

我知道我在某处做错了,xml的格式化(我无法在源头改变)没有帮助......

我收到的错误是“AttributeError:'list'对象没有属性'getchildren'”

1 个答案:

答案 0 :(得分:2)

这样的事情怎么样:

from lxml import etree

root = etree.parse('xml.xml')
rows = root.findall('row')

all_data = []

for row in rows:
    field_dict = {}
    fields = row.findall('field')

    for field in fields:
        field_dict[field.get('name')] = field.text

    print(field_dict)

    all_data.append(field_dict)

print(all_data)


--output:--
{'item 3': 'Accepted', 'item 2': 'Accepted', 'item 1': 'bar 1', 'id': '1', 'name': 'foo 1'}
{'item 3': 'Accepted', 'item 2': 'Declined', 'item 1': 'bar 2', 'id': '2', 'name': 'foo 2'}
{'item 3': 'Declined', 'item 2': 'Accepted', 'item 1': 'bar 3', 'id': '3', 'name': 'foo 3'}


[{'item 3': 'Accepted', 'item 2': 'Accepted', 'item 1': 'bar 1', 'id': '1', 'name': 'foo 1'}, {'item 3': 'Accepted', 'item 2': 'Declined', 'item 1': 'bar 2', 'id': '2', 'name': 'foo 2'}, {'item 3': 'Declined', 'item 2': 'Accepted', 'item 1': 'bar 3', 'id': '3', 'name': 'foo 3'}]

可能在一行中的额外字段将在field_dict中,但您可以忽略它们。或者,如果这对您不起作用,您可以过滤掉垃圾:

from lxml import etree

root = etree.parse('xml.xml')
rows = root.findall('row')

#Create a set:
allowed_names = {
    'id',
    'name',
    'item 1',
    'item 2',
    'item 3'
}

all_data = []


for row in rows:
    field_dict = {}
    fields = row.findall('field')

    for field in fields:
        name_val = field.get('name')

        if name_val in allowed_names:
            field_dict[name_val] = field.text

    print(field_dict)

    all_data.append(field_dict)

print(all_data)

如果它更方便,你可以将all_data定义为字典,并使用id作为键,每个键的值可以是包含其余数据的字典。