3

解析するXMLがありますが、これは非常に難しいことです。

<bundles>
  <bundle>
    <bitstreams>
      <bitstream>
        <id>1234</id>
      </bitstream>
    </bitstream>
    <name>FOO</name>
  </bundle>
  <bundle> ... </bundle>
</bundles>

このXMLを繰り返し処理し、name要素の値が「FOO」であるバンドルのビットストリーム内のすべてのid値を見つけたいと思います。「FOO」という名前ではないバンドルには興味がありません。バンドルには、任意の数のバンドルと任意の数のビットストリームが含まれている可能性があります。

私はFOOバンドルを見つけるために使用してきましたが、これはidtree.findall('./bundle/name')をステップスルーできないリストを返すだけです。

for node in tree.findall('./bundle/name'):
if node.text == 'FOO':
 id_values = tree.findall('./bundle/bitstreams/bitstream/id')
 for value in id_values:
     print value.text

これにより、バンドル'FOO'の値ではなく、すべてのid値が出力されます。

このツリーを反復処理し、 FOOという名前のバンドルを見つけ、このバンドルノードを取得して、そこにネストされたID値を収集するにはどうすればよいですか?ここでXPath引数は正しくありませんか?

私はPythonでlxmlバインディングを使用して作業していますが、XMLパーサーであれば問題ありません。これらは大きなXMLツリーではありません。

4

2 に答える 2

6

xpath目的を達成するために使用できます。次のPythonコードは完璧に機能します:

import libxml2
data = """
<bundles>
  <bundle>
    <bitstreams>
      <bitstream>
        <id>1234</id>
      </bitstream>
    </bitstreams>
    <name>FOO</name>
  </bundle>
</bundles>
"""
doc = xmllib2.parseDoc(data)
for node in doc.xpathEval('/bundles/bundle/name[.="FOO"]/../bitstreams/bitstream/id'):
    print node

または使用lxmldata上記の例と同じ):

from lxml import etree

bundles = etree.fromstring(data)

for node in bundles.xpath('bundle/name[.="FOO"]/../bitstreams/bitstream/id'):
    print(node.text)

出力:

1234

<bitstreams>要素が常に要素の前にある場合は<name>、より効率的なxpath式を使用することもできます。

'bundle/name[.="FOO"]/preceding-sibling::bitstreams/bitstream/id'
于 2012-11-19T19:04:44.887 に答える
2

あなたの質問の1つは、「XPath引数はここで間違っていますか?」でした。ええと、findall()XPath式を受け入れません。ElementPathと呼ばれる簡略化されたバージョンを使用します。また、への2回目の呼び出しfindall()は、最初の呼び出しの結果とはまったく関係がないためid、すべてbundleのsのsを返すだけです。

コードを少し変更するだけでも機能するはずです(基本的にはXPath式と同じです)。

for node in tree.findall('./bundle/name'):
    if node.text != 'FOO':
        continue
    id_values = node.getparent().findall('./bitstreams/bitstream/id')
    for value in id_values:
        print value.text
于 2012-11-19T19:59:06.913 に答える