2

テキストを含むノードの親ノードを取得するにはどうすればよいですか?

re.compile("th[ei]s? .ne")さらに、たとえば以下の検索/フィルタリングの一致する要素として、いくつかの正規表現メカニズムを使用できますか?

いうthis one

html = '''<html>
<head><title></title></head>
<body>
<table>
<tr><td>1a</td><td>2a</td><td>3a</td><td>4a</td><td>5a</td><td>6a</td></tr>
<tr><td>1b</td><td>2b</td><td>3b</td><td>4b</td><td>5b</td><td>6b</td></tr>
<tr><td>1c</td><td>2c</td><td>3c</td><td>4c</td><td>5c</td><td>6c this one</td></tr>
</table>
<div><div>
<table>
<tr><td>1A</td><td>2A</td><td>3A</td><td>4A</td><td>5A</td><td>6A</td></tr>
<tr><td>1B</td><td>2B</td><td>3B</td><td>4B</td><td>5B</td><td>6B</td></tr>
<tr><td>1C</td><td>2C</td><td>3C</td><td>4C</td><td>5C</td><td>6C</td></tr>
</table>this one
</div></div>
</body>
</html>'''

私は返すイテレータが欲しい:

<td>6c this one</td>

その後:

<div>
<table>
<tr><td>1A</td><td>2A</td><td>3A</td><td>4A</td><td>5A</td><td>6A</td></tr>
<tr><td>1B</td><td>2B</td><td>3B</td><td>4B</td><td>5B</td><td>6B</td></tr>
<tr><td>1C</td><td>2C</td><td>3C</td><td>4C</td><td>5C</td><td>6C</td></tr>
</table>this one
</div>

私は試した:

import lxml.html
root = lxml.html.document_fromstring(html)
root.xpath("//text()[contains(., one)]")

import xml.etree.ElementTree as ET
for e in ET.fromstring(html).getiterator():
    if e.text and e.text.find('one') != -1:
        print "Found string %r, element = %r" % (e.text, e)

しかし、私が持つことができる最高のものは、this oneそれ自体を含むノードです...このテキストを含む親を探している間。divまたはテーブルは単なる例であることに注意してください.xml要素をフィルタリングするのではなく、「これ」を見つけた後、親に戻る必要があることに注意してthis oneください。含まれています。

(これは html であり、適切にフォーマットされた xml ではないことにも注意してください。2 番目this oneは xml タグでラップする必要があると思います)

編集:

>>> root.xpath("//*[contains(child::*/text(), 'one')]") # why empty parent?
[]
>>> root.xpath("//*[contains(text(), 'one')]") # i expected to have a list with two elements td and div
[<Element td at 0x280b600>]
>>> root.xpath("//*[child::*[contains(text(), 'one')]]") # if parent: expected tr and div, if not parent expected table or div, still missing one
[<Element tr at 0x2821f30>]

ところで、最後の使用は問題ありません:

import xml.etree.ElementTree as ET
import lxml.html
#[... here add html = """...]
root = lxml.html.document_fromstring(html)
for i, x in enumerate(root.xpath("//text()[contains(., 'one')]/parent::*")):
    print "%s => \n\t" % i, ET.tostring(x).replace("\n", "\n\t")

生産:

0 => 
    <td>6c this one</td>
1 => 
    <div>
    <table>
    <tr><td>1A</td><td>2A</td><td>3A</td><td>4A</td><td>5A</td><td>6A</td></tr>
    <tr><td>1B</td><td>2B</td><td>3B</td><td>4B</td><td>5B</td><td>6B</td></tr>
    <tr><td>1C</td><td>2C</td><td>3C</td><td>4C</td><td>5C</td><td>6C</td></tr>
    </table>this one
    </div>
4

2 に答える 2

5

出力例に基づいて、指定された text を含む要素を取得したいようですone。あなたの説明は、このノードの親が欲しいと言っています。

この仮定に基づいて、次の XPath を使用して目的のノードを取得できます。

//*[contains(text(), 'one')]

このノードの親が本当に必要な場合は、次のことができます

//*[child::*[contains(text(), 'one')]]

ところで、ご覧のとおり、述語を使用してノードを取得したので、XML ノードをフィルター処理しました。の意見では、これはより論理的で読みやすいアプローチです. ただし、次のようなことを行うこともできます。これは、提案されたソリューションにより適しています。

//text()[contains(., 'one')]/parent::*
于 2013-06-18T14:17:36.210 に答える
1
>>> root.xpath("//*[contains(child::*/text(), 'one')]") # why empty parent?
[]

この XPath 式は、最初の孫テキスト ノードに「1」が含まれるすべての要素を選択します。の最初の引数contains()は文字列であると想定されるため、XPath はの結果の最初のノードをchild::*/text()取得し、その文字列値を取得します。最初の孫として "one" を含むテキスト ノードを持つ要素がないため、答えは空のノード リストです。

>>> root.xpath("//*[contains(text(), 'one')]")
# i expected to have a list with two elements td and div
[<Element td at 0x280b600>]

同じ理由で、この XPath 式は、最初のテキスト ノードの子に「1」が含まれるすべての要素を選択します。<td>が選択されているのはそのためですが、そう<div>ではありません。「one」を含む div の子テキスト ノードは、最初の子テキスト ノードではありません。

>>> root.xpath("//*[child::*[contains(text(), 'one')]]")
# if parent: expected tr and div,
# if not parent expected table or div, still missing one
[<Element tr at 0x2821f30>]

これは、前の式と同じ制限に直面しています。

@dirkk が提案した最後の解決策を試しましたか?

//text()[contains(., 'one')]/parent::*

これにより、複数のノードを の最初の引数として渡す際の問題を回避できますcontains()

于 2013-06-19T17:45:05.290 に答える