我一直在努力,它解析外部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.next
和continue
/在尝试不同的语句。
任何帮助,将不胜感激!
更新
一些额外的信息:这是行,其中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
的.
在这个地方应该是一个单引号(照片的)。
我也发现了这个问题 ,它不提供解决方案。
如果问题是实际的字符编码的问题,而不是畸形XML时,最简单的,也可能是最有效的解决办法是在文件读取点来对付它。 像这样:
import codecs
from lxml import etree
events = ("start", "end")
reader = codecs.EncodedFile(xmlfile, 'utf8', 'utf8', 'replace')
context = etree.iterparse(reader, events=events)
这将导致通过被替换的非UTF8可读字节“?”。 还有一些其他的选择; 请参阅编解码器组件文件更多。
由于该问题是由非法的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()
我使用了类似的一段代码:
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)
我在我的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()