0

「xmltodict」ユーティリティを使用してストリーミング モードで解析したい約 3 GB のサイズのかなり大きな XML ファイルがあります。私が持っているコードは、各項目を反復処理して辞書項目を形成し、メモリ内の辞書に追加して、最終的に json としてファイルにダンプします。

私は小さなxmlデータセットで次のように完全に動作しています:

    import xmltodict, json
    import io

    output = []

    def handle(path, item):
       #do stuff
       return

    doc_file = open("affiliate_partner_feeds.xml","r")
    doc = doc_file.read()        
    xmltodict.parse(doc, item_depth=2, item_callback=handle)

    f = open('jbtest.json', 'w')
    json.dump(output,f)

大きなファイルでは、次のようになります。

Traceback (most recent call last):
  File "jbparser.py", line 125, in <module>
    **xmltodict.parse(doc, item_depth=2, item_callback=handle)**
  File "/usr/lib/python2.7/site-packages/xmltodict.py", line 248, in parse
    parser.Parse(xml_input, True)
  OverflowError: size does not fit in an int

xmltodict.py 内の例外の正確な場所は次のとおりです。

def parse(xml_input, encoding=None, expat=expat, process_namespaces=False,
          namespace_separator=':', **kwargs):

        handler = _DictSAXHandler(namespace_separator=namespace_separator,
                                  **kwargs)
        if isinstance(xml_input, _unicode):
            if not encoding:
                encoding = 'utf-8'
            xml_input = xml_input.encode(encoding)
        if not process_namespaces:
            namespace_separator = None
        parser = expat.ParserCreate(
            encoding,
            namespace_separator
        )
        try:
            parser.ordered_attributes = True
        except AttributeError:
            # Jython's expat does not support ordered_attributes
            pass
        parser.StartElementHandler = handler.startElement
        parser.EndElementHandler = handler.endElement
        parser.CharacterDataHandler = handler.characters
        parser.buffer_text = True
        try:
            parser.ParseFile(xml_input)
        except (TypeError, AttributeError):
            **parser.Parse(xml_input, True)**
        return handler.item

これを回避する方法はありますか?私の知る限り、xmlparserオブジェクトは公開されていないので、遊んで「int」を「long」に変更できます。さらに重要なことに、ここで実際に何が起こっているのでしょうか? これに関するリードを本当に感謝します。ありがとう!

4

1 に答える 1

0

ファイル全体をメモリに読み取ってから全体として解析する代わりに、ファイルを非シリアル化する (またはストリームとして使用する) ために、 marshal.load(file) または marshal.load(sys.stdin) を使用してみてください。

例を次に示します。

>>> def handle_artist(_, artist):
...     print artist['name']
...     return True
>>> 
>>> xmltodict.parse(GzipFile('discogs_artists.xml.gz'),
...     item_depth=2, item_callback=handle_artist)
A Perfect Circle
Fantômas
King Crimson
Chris Potter
...

標準入力:

import sys, marshal
while True:
    _, article = marshal.load(sys.stdin)
    print article['title']
于 2016-02-13T10:39:34.757 に答える