Python の ElementTree を使用して、ノードからすべてのテキストを抽出し、その要素のタグを削除してテキストのみを保持するにはどうすればよいですか?
たとえば、次のものがあるとします。
<tag>
Some <a>example</a> text
</tag>
戻りたいですSome example text
。どうすればこれを行うことができますか?これまでのところ、私が取ったアプローチはかなり悲惨な結果をもたらしました。
Python の ElementTree を使用して、ノードからすべてのテキストを抽出し、その要素のタグを削除してテキストのみを保持するにはどうすればよいですか?
たとえば、次のものがあるとします。
<tag>
Some <a>example</a> text
</tag>
戻りたいですSome example text
。どうすればこれを行うことができますか?これまでのところ、私が取ったアプローチはかなり悲惨な結果をもたらしました。
Python 3.2+ で実行している場合は、itertext
.
itertext
この要素とすべてのサブ要素をドキュメント順にループするテキスト反復子を作成し、すべての内部テキストを返します。
import xml.etree.ElementTree as ET
xml = '<tag>Some <a>example</a> text</tag>'
tree = ET.fromstring(xml)
print(''.join(tree.itertext()))
# -> 'Some example text'
下位バージョンの Python で実行している場合は、クラスにアタッチすることでの実装を再利用できます。その後、上記とまったく同じように呼び出すことができます。itertext()
Element
# original implementation of .itertext() for Python 2.7
def itertext(self):
tag = self.tag
if not isinstance(tag, basestring) and tag is not None:
return
if self.text:
yield self.text
for e in self:
for s in e.itertext():
yield s
if e.tail:
yield e.tail
# if necessary, monkey-patch the Element class
if 'itertext' not in ET.Element.__dict__:
ET.Element.itertext = itertext
xml = '<tag>Some <a>example</a> text</tag>'
tree = ET.fromstring(xml)
print(''.join(tree.itertext()))
# -> 'Some example text'
ドキュメントにあるように、中間タグなしでテキストのみを読みたい場合は、すべての属性text
とtail
属性を正しい順序で再帰的に連結する必要があります。
ただし、最近の十分なバージョン (2.7 および 3.2 の stdlib のものを含みますが、2.6 または 3.1 のものは含まれず、現在リリースされている両方のバージョンとElementTree
PyPIlxml
のバージョン) は、tostring
メソッドで自動的にこれを行うことができます。
>>> s = '''<tag>
... Some <a>example</a> text
... </tag>'''
>>> t = ElementTree.fromstring(s)
>>> ElementTree.tostring(s, method='text')
'\n Some example text\n'
テキストから空白も取り除きたい場合は、手動で行う必要があります。あなたの単純なケースでは、それは簡単です:
>>> ElementTree.tostring(s, method='text').strip()
'Some example text'
ただし、中間タグ内の空白を取り除きたい、より複雑なケースでは、おそらくtext
s とtail
s を再帰的に処理する必要があります。それほど難しいことではありません。属性がNone
. たとえば、独自のコードをフックできるスケルトンは次のとおりです。
def textify(t):
s = []
if t.text:
s.append(t.text)
for child in t.getchildren():
s.extend(textify(child))
if t.tail:
s.append(t.tail)
return ''.join(s)
このバージョンは、 および が または であることが保証されている場合にのみtext
機能しtail
ます。手動で構築したツリーの場合、それが正しいとは限りません。str
None