XML解析-ElementTree対SAXおよびDOM
-
08-07-2019 - |
質問
Pythonには、XMLを解析するいくつかの方法があります...
SAX を使用した解析の基本を理解しています。イベント駆動型APIを使用して、ストリームパーサーとして機能します。
DOM パーサーも理解しています。 XMLをメモリに読み取り、Pythonでアクセスできるオブジェクトに変換します。
一般的に言えば、何をする必要があるか、メモリの制約、パフォーマンスなどに応じて2つから簡単に選択できました。
(うまくいけば今のところ正解です。)
Python 2.5以降には、 ElementTree もあります。これはDOMやSAXと比較してどうですか?どちらに似ていますか?以前のパーサーよりも優れているのはなぜですか?
解決
ElementTreeはXMLツリーを(基本的に)リストの構造として表し、属性は辞書として表されるため、使いやすくなります。
ElementTreeはDOMよりもXMLツリーに必要なメモリがはるかに少なく(したがって高速です)、 iterparse
を介した解析オーバーヘッドはSAXと同等です。さらに、 iterparse
は部分的な構造を返します。構造を処理するとすぐに破棄することで、解析中にメモリ使用量を一定に保つことができます。
ElementTreeは、Python 2.5のように、本格的なXMLライブラリと比較して小さな機能セットしかありませんが、多くのアプリケーションには十分です。検証パーサーまたは完全なXPathサポートが必要な場合は、lxmlが最適です。長い間、以前は非常に不安定でしたが、2.1以降、問題はありませんでした。
ElementTreeは、ノードがその親および兄弟にアクセスできるDOMとは異なります。テキストノードは実際のノードとして扱われないため、データストアではなく実際のドキュメントを処理することも少し面倒です。 XMLスニペットで
<a>This is <b>a</b> test</a>
文字列 test
は、要素 b
のいわゆる tail
になります。
一般に、Pythonを使用したすべてのXML処理のデフォルトとしてElementTreeを、特定の問題の解決策としてDOMまたはSAXをお勧めします。
他のヒント
最小限のDOM実装:
リンク 。
Pythonは、XML DOM( xml.dom )の完全なW3C標準実装と、最小の xml.dom.minidom を提供します。後者は、完全な実装よりも単純で小さくなります。ただし、「解析の観点」からは、標準DOMのすべての長所と短所があります。つまり、すべてをメモリにロードします。
基本的なXMLファイルの検討:
<?xml version="1.0"?>
<catalog>
<book isdn="xxx-1">
<author>A1</author>
<title>T1</title>
</book>
<book isdn="xxx-2">
<author>A2</author>
<title>T2</title>
</book>
</catalog>
minidom を使用して可能なPythonパーサーは次のとおりです。
import os
from xml.dom import minidom
from xml.parsers.expat import ExpatError
#-------- Select the XML file: --------#
#Current file name and directory:
curpath = os.path.dirname( os.path.realpath(__file__) )
filename = os.path.join(curpath, "sample.xml")
#print "Filename: %s" % (filename)
#-------- Parse the XML file: --------#
try:
#Parse the given XML file:
xmldoc = minidom.parse(filepath)
except ExpatError as e:
print "[XML] Error (line %d): %d" % (e.lineno, e.code)
print "[XML] Offset: %d" % (e.offset)
raise e
except IOError as e:
print "[IO] I/O Error %d: %s" % (e.errno, e.strerror)
raise e
else:
catalog = xmldoc.documentElement
books = catalog.getElementsByTagName("book")
for book in books:
print book.getAttribute('isdn')
print book.getElementsByTagName('author')[0].firstChild.data
print book.getElementsByTagName('title')[0].firstChild.data
xml.parsers.expat はExpat非検証XMLパーサー(docs.python.org/2/library/pyexpat.html)へのPythonインターフェースであることに注意してください。
xml.dom パッケージは例外クラス DOMException も提供しますが、 minidom ではサポートされていません!
ElementTree XML API:
リンク。
ElementTree ははるかに使いやすく、XML DOMよりも少ないメモリで済みます。さらに、C実装が利用可能です( xml.etree.cElementTree )。
ElementTree を使用して可能なPythonパーサーは次のとおりです。
import os
from xml.etree import cElementTree # C implementation of xml.etree.ElementTree
from xml.parsers.expat import ExpatError # XML formatting errors
#-------- Select the XML file: --------#
#Current file name and directory:
curpath = os.path.dirname( os.path.realpath(__file__) )
filename = os.path.join(curpath, "sample.xml")
#print "Filename: %s" % (filename)
#-------- Parse the XML file: --------#
try:
#Parse the given XML file:
tree = cElementTree.parse(filename)
except ExpatError as e:
print "[XML] Error (line %d): %d" % (e.lineno, e.code)
print "[XML] Offset: %d" % (e.offset)
raise e
except IOError as e:
print "[XML] I/O Error %d: %s" % (e.errno, e.strerror)
raise e
else:
catalogue = tree.getroot()
for book in catalogue:
print book.attrib.get("isdn")
print book.find('author').text
print book.find('title').text
ElementTreeのparse()はDOMに似ていますが、iterparse()はSAXに似ています。私の意見では、ElementTreeはAPIを使いやすくするという点でDOMやSAXよりも優れています。
ElementTreeには、より多くのpythonic APIがあります。また、現在標準ライブラリに含まれているため、使用すると依存関係が減少します。
実際には lxml を好みます。ElementTreeのようなAPIを備えていますが、優れた追加機能があり、パフォーマンスも優れています。