【问题标题】:Python Element Tree ParseErrorPython Elementtree ParseError
【发布时间】:2025-12-20 10:45:06
【问题描述】:

提前感谢您的所有帮助!

我正在处理一个大型文本数据集。每个文件包含多个.xml 文件。 其中一个文件可能如下所示(重现下面提到的错误的最小示例):

'\'<?xml version="1.0" encoding="ISO-8859-1" ?>\\n<!DOCTYPE doc SYSTEM "abnml-1.0b.dtd">\\n<doc msize="000002515" md5="748077a08df8db4a6472a52ed7f31b87" sysId="sbknwsarchp1" destination="AW" distId="    " transmission-date="                " >\\n<abnml publisher="ABC" docdate="20000101" product="ABC" seq="101" xml:lang="en-us" >\\n<head>\\n<copyright year="2000" holder="ABC &amp; Company, Inc." ></copyright>\\n<docdata>\\n<abc>\\n<ABC-news news-source="ABC" origin="AA" service-id="CO" >\\n<abc-press/>\\n<abc-urban>0</abc-urban>\\n<abc-mdata brand="AB" temp-perm="P" retention="N" hot="N" original-source="FW" accession-number="11111" page-citation="" display-date="22000101T164800.000Z" >\\n<abc-coding>\\n<abc-industry>\\n<c>I/BAN</c>\\n<c>I/SCR</c>\\n</abc-industry>\\n<abc-sub>\\n<c>N/CMR</c>\\n<c>N/DJI</c>\\n<c>N/DJN</c>\\n<c>N/EWR</c>\\n<c>N/WER</c>\\n<c>N/BON</c>\\n<c>N/ABS</c>\\n<c>N/ABWI</c>\\n<c>N/TPC</c>\\n<c>N/Y2\\x0b</c>\\n</abc-sub>\\n<abc-mark>\\n<c>M/NND</c>\\n</abc-mark>\\n<abc-prod>\\n<c>P/AS03</c>\\n</abc-prod>\\n</abc-cod>\\n</djn-mdata>\\n</abc-news>\\n</abc>\\n</docdata>\\n</head>\\n<body>\\n<headline prefix="="  brand-display="AB" >\\nJames Bond Is OK</headline>\\n<text>\\n<pre>\\n \\n </pre>\\n<p>\\n  NEW --The new year. </p>\\n<p>\\n  &quot;It was as usual (N`w Year&apos;s Eve) night, on Monday,&quot; said the. </p>\\n<p>\\n  at|the agency. </p>\\n<p>\\n  The firm. </p>\\n<p>\\n  In addition Jan. 1, 2200, didn&apos;t recommended early last year &quot;repurchase&quot; fist few days of January. involve wire&#233;&#219; measure.&quot; </p>\\n<p>\\n  And, to be fair, mend&#225;tion: they&apos;ve 2000,  there isn&apos;t a need eur&#227;&#219;&gt;+ </p>\\n<p>\\n  (END) </p>\\n<p>\\n  January 01, 2200 11:48 ET (16:48 GMT)</p>\\n</text>\\n</body>\\n</abnml>\\n</doc>\''

我第一个提取必要部分的解决方案是使用 Python 的标准库 xml.etree.ElementTree。请在下面找到一个最小的工作示例:

import xml.etree.ElementTree as ET

with open('EXAMPLE.nml', "rt") as file: 
    contents = file.read()

root = ET.fromstring(contents) 

在上面的示例文本上运行 sn-p 时,返回以下错误:

ParseError: not well-formed (invalid token): line 28, column 7

在广泛浏览了心爱的 * 之后,我已经尝试了以下替代方案:

  • 使用lxml.etree 库,将文件读入文件(因为它允许“恢复”选项):

from lxml import etree

with open('EXAMPLE.nml', "rb") as file: 
    contents = file.read()

parser = etree.XMLParser(recover=True)
root = etree.fromstring(contents,parser=parser)

此解决方案实际上适用于该文件,但对其他文件返回相同的错误。总体问题是数据集相当庞大和复杂。该脚本必须在服务器上运行,不可能为所有个别情况编写小的变通方法或测试每个文件。

其他帖子上的一些 cmets 建议“修复生成文件而不是 .xml 文件本身的过程”。但是,鉴于数据集是外部提供的,这根本不可行。

  • 作为另一种可能性,我尝试在解析之前对文件进行解码和重新编码,因为这似乎已经解决了其他用户的问题(尽管有些人提到该解决方案似乎不适用于较新的版本)。这对我也不起作用。
  • 作为最后一个选项,我尝试使用BeautifulSoup。我对这个选项有两个问题:
    • 使用 lxml 解析器给我留下了一个空的解析树
    • 使用标准 bs4 解析器/或 html.parser 会导致解析树,但是,结构似乎被搞砸了,以至于在我的代码的后续步骤中读取适当的子级失败。

我正在运行以下版本(在寡妇机器上):

  • 蟒蛇(蟒蛇):3.8.10
  • lxml:4.6.3
  • beautifulsoup4: 4.9.3

如果有任何提示或建议,我们将不胜感激。非常感谢!

【问题讨论】:

  • 所以看起来你的问题是\\x0b,它是一个垂直标签。目前尚不清楚这是否具有任何语义含义,但我认为您最终可能需要在解析之前清理此 XML。
  • @KyleParsons 非常感谢您的快速回复!很抱歉不得不删除很多文本(鉴于它是外部的,我不得不让它基本上毫无意义)。无论哪种方式,我实际上都在考虑使用正则表达式。但是,正如我在问题中提到的,数据集非常庞大,几乎不可能知道哪些标记可能会在其他数据示例中产生错误(如果不相同)。您是否想到了任何足够通用的清洁步骤 - 希望 - 处理这些问题,但又不是太笼统且可能具有破坏性?非常感谢任何 cmets!
  • @KyleParsons 快速更新:clean = re.sub('\x0b','', EXAMPLE.decode()) 然后ET.fromstring(clean) 似乎至少解决了这个特定案例的问题!但是,我几乎可以肯定,其他元素可能会在其他文件中引发类似的错误。有没有办法动态读出麻烦的令牌,然后用re 将其删除,例如try except 声明还是什么?谢谢!

标签: python xml parsing beautifulsoup elementtree


【解决方案1】:

再次感谢 cmets 的帮助!

经过一些测试,我找到了两种可能的解决方案来解决我的问题。因为 - 据我所知 - 它们似乎没有记录在例如所以,我希望它们对遇到类似问题的其他人有用。

  • 如前所述,我也尝试使用BeautifulSoupbs4。最初的问题可以通过以下方式解决:

from bs4 import BeautifulSoup as bs
import lxml

with open('EXAMPLE.nml', "rb") as file: 
contents = file.read()
    
soup = bs(contents, features="lxml")  

为此,必须先安装lxml,然后再安装bs4。这应该会自动为bs4 安装lxml 解析器。如原问题所述,缺点是生成的解析树具有不同的结构,并且必须调整代码的后面部分。

  • 解决方案 2:其中一个 cmets 将我推向了这个方向。我没有使用bs4,而是实现了以下代码:

from lxml import etree
import re 



 try:
        parser = etree.XMLParser(ns_clean=True, recover=True)
        root = etree.fromstring(contents,parser=parser) 
                
 except:
        fixed = re.sub(r"[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]", "", contents.decode()).encode()
        parser = etree.XMLParser(ns_clean=True, recover=True)
        root = etree.fromstring(fixed,parser=parser) 

此解决方案的优点是无需更改其余代码。它似乎积极地解决了这个问题,即使使用 ns_clean=True, recover=True 参数,lxml 解析器似乎在某些文件上也失败了。

【讨论】: