2011-01-14 28 views
13

私はこのようなXMLがあります。効率的な方法は

<a> 
    <b>hello</b> 
    <b>world</b> 
</a> 
<x> 
    <y></y> 
</x> 
<a> 
    <b>first</b> 
    <b>second</b> 
    <b>third</b> 
</a> 

私はすべての<a><b>タグを反復処理する必要があるが、しかし、私は、ドキュメント内にあるどのようにそれらの多くは知りません。

from lxml import etree 

doc = etree.fromstring(xml) 

atags = doc.xpath('//a') 
for a in atags: 
    btags = a.xpath('b') 
    for b in btags: 
      print b 

それは動作しますが、私はかなり大きなファイルを持っている、とcProfilexpathは使用することは非常に高価であることを私に示していますので、私はそれを処理するためにxpathを使用しています。

xml要素の無制限数を反復処理する効率的な方法があるのだろうか?

+1

「かなり大きい」をメガバイトに変換してください。 –

答えて

17

XPathは高速である必要があります。

doc = etree.fromstring(xml) 
btags = doc.xpath('//a/b') 
for b in btags: 
    print b.text 

それが十分に高速でない場合、あなたはLiza Daly's fast_iterを試みることができる:あなたは、XPathの数が一つに呼び出しを減らすことができます。これには、最初にetree.fromstringでXML全体を処理する必要がなく、子ノードの訪問後に親ノードが破棄されるという利点があります。これらの両方がメモリ要件を削減するのに役立ちます。以下はa modified version of fast_iterであり、もはや必要でなくなった他の要素を削除することにもっと積極的です。

def fast_iter(context, func, *args, **kwargs): 
    """ 
    fast_iter is useful if you need to free memory while iterating through a 
    very large XML file. 

    http://lxml.de/parsing.html#modifying-the-tree 
    Based on Liza Daly's fast_iter 
    http://www.ibm.com/developerworks/xml/library/x-hiperfparse/ 
    See also http://effbot.org/zone/element-iterparse.htm 
    """ 
    for event, elem in context: 
     func(elem, *args, **kwargs) 
     # It's safe to call clear() here because no descendants will be 
     # accessed 
     elem.clear() 
     # Also eliminate now-empty references from the root node to elem 
     for ancestor in elem.xpath('ancestor-or-self::*'): 
      while ancestor.getprevious() is not None: 
       del ancestor.getparent()[0] 
    del context 

def process_element(elt): 
    print(elt.text) 

context=etree.iterparse(io.BytesIO(xml), events=('end',), tag='b') 
fast_iter(context, process_element) 

Liza Daly's article大規模なXMLファイルの解析では、あまりにも参考になるかもしれません。記事によると、fast_iterのlxmlは、cElementTreeiterparseより速くなる可能性があります。 (表1参照)。

+0

fast_iterコードの 'doc = etree.fromstring(xml)'の目的は何ですか? –

+0

@John Machin:コピー貼り付けエラー。それを指摘してくれてありがとう。 – unutbu

+0

iterparse speed war:1つの特定のタグを選択すると、lxmlの方が速く、複数のタグを調べる必要がある一般的な解析では、cElementTreeが高速になります。 –

10

iter

>>> for tags in root.iter('b'):   # root is the ElementTree object 
...  print tags.tag, tags.text 
... 
b hello 
b world 
b first 
b second 
b third 
+0

そのリンクは死んでいます。 http://lxml.de/tutorial.html#tree-iteration –

5

使用すると、iterparse:

import lxml.etree as ET 
    for event, elem in ET.iterparse(filelike_object): 
     if elem.tag == "a": 
      process_a(elem) 
      for child in elem: 
       process_child(child) 
      elem.clear() # destroy all child elements 
     elif elem.tag != "b": 
      elem.clear() 

注意これは、すべてのメモリを節約しませんが、私はこの技術を用いてGBを超えるのXMLストリームを通じて苦労することができましたことを。

それは、Pythonに付属しており、そのiterparsethe lxml docsによると、lxml.etreeiterparseよりも高速です... import xml.etree.cElementTree as ETをお試しください:大きなファイルの高パーサのスループットを必要とするアプリケーションのために "「」

、そしてそれはほとんどありませんシリアル化を行わない場合はcETが最適です。また、メモリに収まらない大規模なXMLデータセットから少量のデータを集める、または集約するiterparseアプリケーションの場合もありますが、往復パフォーマンスの場合、lxmlは入力文書が出力よりもかなり大きくならない場合は、lxmlが明白な勝者です。 "" "

-2

bs4は非常に便利です。

from bs4 import BeautifulSoup 
raw_xml = open(source_file, 'r') 
soup = BeautifulSoup(raw_xml) 
soup.find_all('tags')