解析 XML 文件时需要类似字节的对象,而不是“str”

问题描述 投票:0回答:2

我正在尝试解析如下所示的 xml。我想提取有关类别的信息,即 ID、家长 ID 等:

<?xml version="1.0" encoding="UTF-8"?>
<test timestamp="20210113">
<kategorien>
    <kategorie id="1" parent_id="0">
        Sprache
    </kategorie>
</kategorien>
</test>

我正在尝试这个

fields = ['id', 'parent_id']

with open('output.csv', 'wb') as fp:
    writer = csv.writer(fp)
    writer.writerow(fields)
    tree = ET.parse('./file.xml')
    # from your example Locations is the root and Location is the first level
    for elem in tree.getroot():
        writer.writerow([(elem.get(name) or '').encode('utf-8') 
            for name in fields])

但我收到此错误:

in <module>
    writer.writerow(fields)
TypeError: a bytes-like object is required, not 'str'

即使我已经在代码中使用了

encode('utf-8') 
。我怎样才能摆脱这个错误?

python python-3.x xml utf-8 encode
2个回答
1
投票

编辑2 如果想查找嵌套属性或子类,有两种方法:

  1. 您可以使用嵌套循环:
for elem in root:
    for child in elem:
        print([(child.attrib.get(name) or 'c') for name in fields])

输出:

['1','0']

在这里,它还可以返回具有

id
parent_id
但不包含名称
kategorie
的类。

  1. 如果您想以更高的性能和更少的内存来执行任务:
for elem in root.iter('kategorie'):
    print([(elem.attrib.get(name) or 'c') for name in fields])

输出:

['1','0']

对于此方法,它将返回名为

kategorie
的每个类和子类。

编辑1:对于评论中的问题:

<?xml version="1.0"?>
<kategorien>
    <kategorie id="1" parent_id="0">
        Sprache
    </kategorie>
</kategorien>

对于上面的

xml
文件,代码似乎运行得很好:

fields = ['id', 'parent_id']

for elem in tree.getroot():
    print([(elem.attrib.get(name) or 'c') for name in fields])

输出:

['1','0']

原答案: 看起来您正在寻找错误的位置。错误实际上发生在

writer.writerow(fields)

fields
是一个包含
str
而不是
byte
的列表,这就是它给你错误的原因。我建议您将写入类型从
wb
更改为
w
,但看看其余的代码,看起来您想用
byte
写入。

writer.writerow([x.encode('utf-8') for x in fields])

encode()
只是将您的数据转换为
byte
形式。


0
投票

我看到两个问题。首先,您不需要自己进行编码。打开不带“b”二进制标志的文件并跳过 .encode。文件对象将为您进行编码。您看到的错误来自包含未编码字符串的

['id', 'parent_id']
列表。但如果你一开始就不以二进制方式打开,那就不是问题。

其次,您迭代了错误的元素。在循环中添加

print(elem)
,您就会看到。相反,您可以使用
findall
和伪 xpath 来获取所需的元素。

import csv
import xml.etree.ElementTree as ET

fields = ['id', 'parent_id']

with open('output.csv', 'w') as fp:
    writer = csv.writer(fp)
    writer.writerow(fields)
    tree = ET.parse('./file.xml')
    # from your example Locations is the root and Location is the first level
    for elem in tree.getroot().findall('kategorien/kategorie'):
        writer.writerow([(elem.get(name) or '') 
            for name in fields])
© www.soinside.com 2019 - 2024. All rights reserved.