解析在Python巨大,严重编码XML文件(Parsing huge, badly encoded

2019-06-26 03:33发布

我一直在努力,它解析外部XML的文件中的代码。 其中一些文件是巨大的,高达千兆字节的数据。 不用说,这些文件需要被解析为一个流,因为它们加载到内存是太低效,往往导致内存不足的烦恼。

我已经使用了库minidom命名,ElementTree的,cElementTree和我目前正在使用LXML。 现在我有一个工作,相当节省内存的脚本,使用lxml.etree.iterparse 。 问题是,一些我需要解析包含编码错误(他们做广告为UTF-8,但含有不同编码的字符)的XML文件。 当使用lxml.etree.parse这可以通过使用固定recover=True定制解析器的选择,但iterparse不接受自定义分析器。 (参见: 这个问题 )

我当前的代码如下所示:

from lxml import etree
events = ("start", "end")
context = etree.iterparse(xmlfile, events=events)
event, root_element = context.next() # <items>
for action, element in context:
    if action == 'end' and element.tag == 'item':
    # <parse>
    root_element.clear() 

当错误iterparse遇到人品不好(在这种情况下,这是一个^Y ):

lxml.etree.XMLSyntaxError: Input is not proper UTF-8, indicate encoding !
Bytes: 0x19 0x73 0x20 0x65, line 949490, column 25

我甚至不希望这些数据进行解码,我就可以将其删除。 不过,我不知道有什么办法跳过元素-我想context.nextcontinue /在尝试不同的语句。

任何帮助,将不胜感激!

更新

一些额外的信息:这是行,其中iterparse失败:

<description><![CDATA:[musea de la photographie fonds mercator. Met meer dan 80.000 foto^Ys en 3 miljoen negatieven is het Muse de la...]]></description>

据etree,在字节出现错误0x19 0x73 0x20 0x65
据hexedit的, 19 73 20 65转换为ASCII .se
. 在这个地方应该是一个单引号(照片的)。

我也发现了这个问题 ,它不提供解决方案。

Answer 1:

如果问题是实际的字符编码的问题,而不是畸形XML时,最简单的,也可能是最有效的解决办法是在文件读取点来对付它。 像这样:

import codecs
from lxml import etree
events = ("start", "end")
reader = codecs.EncodedFile(xmlfile, 'utf8', 'utf8', 'replace')
context = etree.iterparse(reader, events=events)

这将导致通过被替换的非UTF8可读字节“?”。 还有一些其他的选择; 请参阅编解码器组件文件更多。



Answer 2:

由于该问题是由非法的XML字符造成的,在这种情况下,0x19字节,我决定带他们了。 我发现下面的正则表达式在这个网站 :

invalid_xml = re.compile(u'[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]')

我写这段代码同时节省一个XML饲料,消除非法字节:

conn = urllib2.urlopen(xmlfeed)
xmlfile = open('output', 'w')

while True:
    data = conn.read(4096)
    if data:
        newdata, count = invalid_xml.subn('', data)
        if count > 0 :
            print 'Removed %s illegal characters from XML feed' % count
        xmlfile.write(newdata)

    else:
        break

xmlfile.close()


Answer 3:

我使用了类似的一段代码:

 illegalxml = re.compile(u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')

...

illegalxml.sub("?",mystring)

...

然而,这并没有为所有可能的字符串(400 + MB字符串)工作。

对于最终溶液我用解码/编码,如下所示:

outxml = "C:/path_to/xml_output_file.xml"
with open(outxml, "w") as out:
    valid_xmlstring = mystring.encode('latin1','xmlcharrefreplace').decode('utf8','xmlcharrefreplace')
    out.write(valid_xmlstring) 


Answer 4:

我在我的xml文件,这也是无效XMLCHAR类似的问题与字符“”。 这是因为在XML 1.0版,人物喜欢&#X0,&#xE的是不允许的。 且规则是所有字符组成的正则表达式“&#x的[0-1] [0-9A-E]”是不允许的。 我的目的是纠正一个巨大的XML文件无效字符的基础上,里克的回答,我如下改进它:

import re

invalid_xml = re.compile(r'&#x[0-1]?[0-9a-eA-E];')

new_file = open('new_file.xml','w') 
with open('old_file.xml') as f:
    for line in f:
        nline, count = invalid_xml.subn('',line)
        new_file.write(nline) 
new_file.close()


文章来源: Parsing huge, badly encoded XML files in Python