Python 元素树解析错误

Python Element Tree ParseError

提前感谢您的帮助!

我正在处理一个大型文本数据集。每个文件包含多个 .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) 

当运行在上面的示例文本中使用片段时,返回以下错误:

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

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

:

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)

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

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

我运行正在使用以下版本(在 widows 机器上):

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

再次感谢您的宝贵意见!

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

  • 如问题中所述,我也尝试使用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:其中一条评论将我推向了这个方向。我没有使用 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 解析器似乎在某些文件上失败。