【问题标题】:Parsing nested elements using iterparse() or findall()使用 iterparse() 或 findall() 解析嵌套元素
【发布时间】:2020-12-07 23:34:12
【问题描述】:

我有 xml 文档(用 UTF-8 编码),其结构为:

<Group id= "123">
    <rule id= "abc" level= "low">
    <identity>some text</identity>
    <element1>text</element1>
</Group>

每个文档都有多个 Group 元素,目标是将它们解析为一个电子表格,其中每个组是一行,其中包含 group id、level 以及来自 identity 和 element1 元素的文本。

我有一个使用 findall() 的脚本,当我尝试一次解析一个文档时它可以工作,但是当我尝试一次解析多个文档时,它往往会失败并显示错误:

 File "c:/Documents/Python Projects/Bulkparse.py", line 86, in parseall
    writer.writerow(data)
  File "C:\Program Files (x86)\Python\lib\encodings\cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\x9d' in position 1137: character maps to <undefined>

我查了 '\x9d' 字符代码,它似乎是某种十字图标,它没有出现在我的任何文档中。所以我确定它发生在哪里或为什么会发生。

Findall() 脚本示例:

for child in root.findall('Group'):
  data.append(child.attrib['id'])
  num = child.attrib['id']
  for child in root.findall('Group[@id = "%s"]/Rule'% num ):
    data.append(child.attrib['level'])
    # followed by a for loop for each element needed ending with
    writer.writerow(data)

上述方法有效,除非我正在做大量工作,这给了我上述错误。

只是 findall() 效率太低了吗?我尝试用 iterparse() 编写一些东西,但找不到一种方法让它遍历每个子元素。例如:

for  event, elem in context:
    if elem.tag ==f"Group" and event == 'end':
        data.append(elem.attrib['id'])
        num = elem.attrib['id']
        for event, elem in context :
            if elem.tag ==f"Rule" and event == 'end':
                data.append(elem.attrib['level'])
                print(data)

返回组 id,后跟每个组的等级等级,如 [123、low、high、low、low、low、high..] 等。

使用 iterparse 更好吗?如果是这样,有没有办法让我将它的目标元素标签嵌套在组元素中,就像我对 findall() 所做的那样? 或者有没有办法让 findall() 脚本停止抛出该错误?有没有办法清除每个文档末尾的内存? (假设这会有所帮助) 非常感谢您的帮助。

【问题讨论】:

  • 请提供完整的堆栈跟踪。解码/编码错误通常与读取/写入文件(或类似流)有关,代码中没有显示任何内容。
  • 该错误表明某些编码不匹配。在 UTF-8 中,9d 是一个连续字节(不应单独出现)。在 cp1252 编码中,9d 是未定义的。
  • 既然错误是由writer.writerow(data) 抛出的——writer 是什么?

标签: python python-3.x xml-parsing lxml


【解决方案1】:

通过拆分文档集并搜索继续引发错误的那一半,找出导致问题的文档。虽然您说 '\x9d' 不在您的文档集中,但它必须以不同的编码存在。

您还没有说 XML 文档有什么字符编码 - 也许将 XML 的字符编码更改为 UTF?

如果您没有发现编码问题,您可以将导出过程切换到 XSL 转换,该转换执行 XML 到 csv 的转换。无论如何,这可能会更好。

【讨论】:

  • 他们使用 UTF-8 编码,我按照 Jack 的建议设置为指定编码值,它似乎没有任何效果@Bryn Lewis
【解决方案2】:

在读取包含异常字符的文件时经常出现此问题。尝试解决它的一种方法是在打开 xml 文件时执行以下操作:

with open('myfile.xml', encoding='utf-8') as myfile:
   root = etree.XML(myfile)  #or however you import lxml and your file
   for child in root.findall('Group'):.....
   

这将解决大部分问题。但是我遇到了很多这样的错误,有时我不得不在处理文件之前将更麻烦的字符从文件中实际编辑出来。比如:

[string representation of your file].replace('\x9d','+') 
#or whatever other charcter you want to use to represent a cross.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-23
    • 2015-09-28
    • 2015-03-14
    • 1970-01-01
    • 2023-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多