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

a bytes-like object is required, not 'str' while parsing XML files

提问人:x89 提问时间:1/23/2023 最后编辑:x89 更新时间:10/23/2023 访问量:173

问:

我正在尝试解析如下所示的 xml。我想提取有关 katagorie 的信息,即 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-3.x xml utf-8 编码

评论

0赞 Abdul Aziz Barkat 1/23/2023
当你有字符串而不是字节时,为什么你特别在模式下打开你的文件?wb
0赞 Abdul Aziz Barkat 1/23/2023
注意:您可能想写 因为 是标签,并且您似乎实际上想要遍历 的子项。for elem in tree.getroot()[0]tree.getroot()testkategorien

答:

1赞 Sam 1/23/2023 #1

编辑 2如果要查找有关嵌套属性或子类的信息,有两种方法:

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

输出:

['1', '0']

在这里,它也可以返回具有 和 但没有 name 的类。idparent_idkategorie

  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是一个包含 和 not 的列表,这就是它给你错误的原因。我本来建议您将写入类型从更改为 ,但查看其余代码,看起来您想写入 .strbytewbwbyte

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

encode()只需将您的数据转换为表单。byte

评论

0赞 x89 1/23/2023
不,我不需要编码。我更改为“w”并使用了它,但它无法正确提取元素,因此,我的输出文件中只有“c”writer.writerow([(elem.get(name) or 'c') for name in fields])
0赞 Sam 1/23/2023
你的做法有点不正确。 将只是一个 或位置指针。假设您已设置为 file 的子项,您可以执行 .elemiterablenameattributexml[(elem.attrib.get(name) or 'c') for name in fields]
0赞 Sam 1/23/2023
attrib返回一个字典,其中包含{ <attribute> : <value>}
0赞 Sam 1/23/2023
你能提供一个最小的可重现文件的例子吗?xml
0赞 Sam 1/23/2023
另外,我建议您根据当前面临的问题编辑您的问题。
0赞 tdelaney 1/24/2023 #2

我看到两个问题。首先,您不需要自己进行编码。打开不带“b”二进制标志的文件并跳过 .encode。文件对象将为您进行编码。您看到的错误来自包含未编码字符串的列表。但是,如果您一开始就不以二进制形式打开,那就不是问题了。['id', 'parent_id']

其次,你迭代了错误的元素。在你的循环中添加一个,你会看到。相反,您可以与伪 xpath 一起使用来获取所需的元素。print(elem)findall

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])