11

私は外部XMLファイルを解析するコードに取り組んできました。これらのファイルのいくつかは巨大で、最大ギガバイトのデータです。言うまでもなく、これらのファイルをメモリにロードするのは非常に非効率的であり、OutOfMemoryの問題を引き起こすことが多いため、これらのファイルをストリームとして解析する必要があります。

私はライブラリminiDOM、ElementTree、cElementTreeを使用しており、現在lxmlを使用しています。現在、を使用して、動作する、かなりメモリ効率の高いスクリプトがありlxml.etree.iterparseます。問題は、解析する必要のあるXMLファイルの一部にエンコードエラーが含まれていることです(UTF-8としてアドバタイズされますが、エンコードが異なる文字が含まれています)。これを使用する場合、カスタムパーサーのオプションをlxml.etree.parse使用して修正できますが、カスタムパーサーは受け入れません。(参照:この質問recover=Trueiterparse

私の現在のコードは次のようになります。

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

このデータをデコードしたくはありません。ドロップするだけです。ただし、要素をスキップする方法がわかりません。try /exceptステートメントを試してみました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 65ASCIIに変換されます.s e
.この場所にはアポストロフィ(写真)が必要です。

私はまた、解決策を提供しないこの質問を見つけました。

4

4 に答える 4

9

問題が不正な形式のXMLではなく、実際の文字エンコードの問題である場合、最も簡単でおそらく最も効率的な解決策は、ファイルの読み取りポイントで問題を処理することです。このような:

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

これにより、UTF8で読み取り不可能なバイトが「?」に置き換えられます。他にもいくつかのオプションがあります。詳細については、コーデックモジュールのドキュメントを参照してください。

于 2012-07-09T18:01:52.417 に答える
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()
于 2012-07-10T21:43:38.220 に答える
1

私は同様のコードを使用しました:

 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) 
于 2013-09-01T00:37:06.123 に答える
0

xmlファイルのchar""でも同様の問題が発生しましたが、これも無効なxmlcharです。これは、xmlバージョン1.0では、&#x0、&#xEなどの文字が許可されていないためです。また、正規表現'&#x [0-1]?[0-9A-E]'としてのすべての文字構成は許可されていません。私の目的は、Rikの回答に基づいて、巨大な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()
于 2016-01-08T10:30:26.487 に答える