pythonのlxmlクイックハンド_Element(一)

14216 ワード

The Element class
いずれのプログラミング言語を使用する開発者にとってxmlの処理は常に避けられず、非常に一般的である.lxmlはpython言語の中で最も機能が豊富で、最も使いやすく、同時に性能もかなり良いxml、html処理ライブラリです.ネット上にもlxmlの使い方を紹介する文章がたくさんありますが、任意のサードパーティライブラリ(フレームワーク、新技術)を学ぶには、公式ドキュメントは間違いなく得られない第一手の良い材料です.そこで、他の必要な学生も素早く手に入れるために、マニュアルのThe lxml.etree Tutorial部分について、一部の翻訳を行いました.同時に、私の英語のレベルは有限で、あるいは理解の上で偏差があって、指摘を惜しまないことを望みます.
ElementはElementTree APIにおいて主要なコンテナオブジェクトである.XML tree関数のほとんどはこれによってアクセスされます.これを作成するには、Elementファクトリ関数を使用します.
>>> root = etree.Element("root")

xmlノードのラベル名はtagプロパティからアクセスできます.
>>> print(root.tag)
root

Elementsはxml中で木構造で組織されている.サブノードを作成し、親ノードに追加する必要がある場合は、append()メソッドを使用します.
>>> root.append( etree.Element("child1") )

しかし、(サブノードを作成する)ニーズはこのように一般的であり、SubElementファクトリ関数を使用するより短く、効率的な方法があります.Elementと同様に、同じパラメータを受け入れますが、最初のパラメータとして追加の親ノードパラメータが必要です.
>>> child2 = etree.SubElement(root, "child2")
>>> child3 = etree.SubElement(root, "child3")

さっき作成したxmlをより直感的に理解するには、シーケンス化を使用します.
>>> print(etree.tostring(root, pretty_print=True))
<root>
  <child1/>
  <child2/>
  <child3/>
root>

Elements are lists
(上で作成した)サブノードにより簡単かつ直接アクセスするために、elementsは、従来のpython Listの動作を可能な限り模倣する.
>>> child = root[0]
>>> print(child.tag)
child1

>>> print(len(root))
3

>>> root.index(root[1]) # lxml.etree only!
1

>>> children = list(root)

>>> for child in root:
...     print(child.tag)
child1
child2
child3

>>> root.insert(0, etree.Element("child0"))
>>> start = root[:1]
>>> end   = root[-1:]

>>> print(start[0].tag)
child0
>>> print(end[0].tag)
child3

ElementTree 1.3 and lxml 2.0の前に、Elementの真偽値をチェックして、子供ノードがあるかどうかを判定することができます.子供ノードからなるリストが空の場合:
if root:   #             
    print("The root element has children")

上記の条件テストはもう機能しません.そのため、多くのユーザーは、任意のノードが上記のように条件テストを行い、結果がFalseであることに驚くかもしれません.代替的な方法としてlen(element)を用いることは意味的により明確であり,誤り傾向がより少ないことを意味する.
>>> print(etree.iselement(root))  #   root        Element
True
>>> if len(root):                 #   root       
...     print("The root element has children")
The root element has children

また、lxmlにおけるElementsの動作(2.0以降のバージョンでは)が従来のpython List、元のElementTreeとずれている場合についても説明する必要があります.
>>> for child in root:
...     print(child.tag)
child0
child1
child2
child3
>>> root[0] = root[-1]  # this moves the element in lxml.etree!
>>> for child in root:
...     print(child.tag)
child3
child1
child2

上記の例では、最後のノードは、別の位置にコピーされるのではなく、異なる位置(最初の)に移動される.別の異なる位置に移動すると、元の位置から削除されます.一般的なリストでは、オブジェクトは同じ時点で異なる場所に表示されますが、リストでは最後のノードの参照が最初の場所にのみコピーされるため、リストには同じ2つのオブジェクトが含まれます.
>>> l = [0, 1, 2, 3]
>>> l[0] = l[-1]
>>> l
[3, 1, 2, 3]

元のElementTreeでは、リストのように同じコピー操作を実行できる任意のxmlツリーオブジェクトの任意の場所にElementオブジェクトを配置できます.ノードの任意の変更がtreeに現れるすべての場所に適用されるという明らかな欠点がある.これは必ずしもあなたが望んでいるとは限らない.上記の特殊な処理には、lxml.etreeのいずれかのElementに唯一の親ノードがあり、getparent()で取得でき、元のElementTreeではサポートされていないという利点があります.
>>> root is root[0].getparent()  # lxml.etree only!
True

lxml.etreeでノードを別の場所にコピーしたい場合は、独立した標準ライブラリモジュールcopyのdeepcopy()を使用することを考慮します.
>>> from copy import deepcopy

>>> element = etree.Element("neu")
>>> element.append( deepcopy(root[1]) )

>>> print(element[0].tag)
child1
>>> print([ c.tag for c in root ])
['child3', 'child1', 'child2']

ノードの兄弟ノードにアクセスしたい場合は、次のことができます.
>>> root[0] is root[1].getprevious() # lxml.etree only!
True
>>> root[1] is root[0].getnext() # lxml.etree only!
True

Elements carry attributes as a dict
XMLノードは、Elementファクトリ関数で直接構築できる属性をサポートします.
>>> root = etree.Element("root", interesting="totally")
>>> etree.tostring(root)
b''

属性は無秩序なキー値(key-value)のペアにすぎないため、それらを処理する簡単な方法はElementsのクラス辞書インタフェースを通じて:
>>> print(root.get("interesting"))
totally

>>> print(root.get("hello"))
None
>>> root.set("hello", "Huhu")
>>> print(root.get("hello"))
Huhu

>>> etree.tostring(root)
b''

>>> sorted(root.keys())
['hello', 'interesting']

>>> for name, value in sorted(root.items()):
...     print('%s = %r' % (name, value))
hello = 'Huhu'
interesting = 'totally'

場合によっては、itemの検索をしたいだけか、他の理由で「真実」のクラス辞書オブジェクトを取得し、周辺に渡したいだけで、attribプロパティを使用することができます.
>>> attributes = root.attrib

>>> print(attributes["interesting"])
totally
>>> print(attributes.get("no-such-attribute"))
None

>>> attributes["hello"] = "Guten Tag"
>>> print(attributes["hello"])
Guten Tag
>>> print(root.get("hello"))
Guten Tag

attribは、Element自体がサポートするクラス辞書オブジェクトであることに注意してください.これは、Elementに対する変更がattribに反射されることを意味し、XML treeは、任意のノードのattribがまだ使用されている限り、「アクティブ」な状態を維持します.XML treeに依存しない独立したattribスナップショットを取得するには、辞書にコピーします.
>>> d = dict(root.attrib)
>>> sorted(d.items())
[('hello', 'Guten Tag'), ('interesting', 'totally')]

Elements contain text
Elementsには、次のテキストが含まれます.
>>> root = etree.Element("root")
>>> root.text = "TEXT"

>>> print(root.text)
TEXT

>>> etree.tostring(root)
b'TEXT'

多くのxmlドキュメント(データを主とする)では、テキストが見つかる唯一の場所です.(テキスト)通常treeの下部のリーフノードに包まれる者.しかし、xmlがHTMLなどのラベルテキストとして使用される場合、テキストは異なるノード間にも表示されます.
<html><body>Hello<br/>Worldbody>html>

ここで、ラベルはテキストで囲まれています.これはdocument-style、mixed-contentタイプのxmlでよく言及される.Elementsはtailプロパティを使用してこれをサポートします.XML treeの次のノードまで、ノードに続くテキストが含まれます.
>>> html = etree.Element("html")
>>> body = etree.SubElement(html, "body")
>>> body.text = "TEXT"

>>> etree.tostring(html)
b'TEXT'

>>> br = etree.SubElement(body, "br")
>>> etree.tostring(html)
b'TEXT
' >>> br.tail = "TAIL" >>> etree.tostring(html) b'TEXT
TAIL'

この2つのプロパティ.text、.tailは、XMLドキュメント内の任意のテキストを表示するのに十分です.しかし、Elementをシーケンス化すると、tail textが結果に現れることを常に望んでいます.この目的を達成するために、tostring()関数はキーワードパラメータwith_を受け入れます.tail:
>>> etree.tostring(br)
b'
TAIL'
>>> etree.tostring(br, with_tail=False) # lxml.etree only! b'
'

テキストtextだけが必要で、中間ノードが必要でない場合は、すべてのtext、tail textプロパティを正しい順序で再帰的に接続する必要があります.もう一度tostring()メソッドが活躍し、methodキーワードパラメータを使用します.
>>> etree.tostring(html, method="text")
b'TEXTTAIL'