簡體   English   中英

在 XML 中查找元素兄弟的最 Pythonic 方法

[英]Most Pythonic way to find the sibling of an element in XML

問題:我有以下 XML 片段:

...snip...
<p class="p_cat_heading">DEFINITION</p>
<p class="p_numberedbullet"><span class="calibre10">This</span>, <span class="calibre10">these</span>. </p>
<p class="p_cat_heading">PRONUNCIATION </p>
..snip...

我需要搜索 XML 的全部內容,找到具有文本DEFINITION的標題,並打印相關的定義。 定義的格式不一致並且可以更改屬性/元素,因此捕獲所有內容的唯一可靠方法是讀取具有屬性p_cat_heading的下一個元素。

現在我正在使用以下代碼來查找所有標題:

for heading in root.findall(".//*[@class='p_cat_heading']"):
    if heading.text == "DEFINITION":
        <WE FOUND THE CORRECT HEADER - TAKE ACTION HERE>

我嘗試過的事情:

  • 使用 lxml 的 getnext 方法。 這將獲得下一個具有“p_cat_heading”屬性的兄弟,這不是我想要的。
  • following_sibling - lxml 應該支持這一點,但它拋出“在前綴映射中找不到以下兄弟姐妹”

我的解決方案:

我還沒有完成,但是因為我的 XML 很短,所以我只想獲取所有元素的列表,迭代直到具有 DEFINITION 屬性的元素,然后迭代直到具有 p_cat_heading 屬性的下一個元素。 這個解決方案既可怕又丑陋,但我似乎找不到干凈的替代方案。

我在找什么:

在我們的例子中,一種更 Pythonic 的打印定義的方式是“這個,這些”。 解決方案可以使用 xpath 或其他替代方法。 首選 Python 原生解決方案,但任何事情都可以。

您可以將 BeatifulSoup 與 CSS 選擇器一起用於此任務。 選擇器.p_cat_heading:contains("DEFINITION") ~ .p_cat_heading將選擇所有帶有類p_cat_heading元素,這些元素前面是帶有包含字符串“DEFINITION”的類p_cat_heading的元素:

data = '''
<p class="p_cat_heading">THIS YOU DONT WANT</p>
<p class="p_numberedbullet"><span class="calibre10">This</span>, <span class="calibre10">these</span>. </p>
<p class="p_cat_heading">DEFINITION</p>
<p class="p_numberedbullet"><span class="calibre10">This</span>, <span class="calibre10">these</span>. </p>
<p class="p_cat_heading">PRONUNCIATION </p>'''

from bs4 import BeautifulSoup

soup = BeautifulSoup(data, 'lxml')

for heading in soup.select('.p_cat_heading:contains("DEFINITION") ~ .p_cat_heading'):
    print(heading.text)

印刷:

PRONUNCIATION 

進一步閱讀

CSS 選擇器指南

編輯:

在定義之后選擇直接兄弟:

data = '''
<p class="p_cat_heading">THIS YOU DONT WANT</p>
<p class="p_numberedbullet"><span class="calibre10">This</span>, <span class="calibre10">these</span>. </p>
<p class="p_cat_heading">DEFINITION</p>
<p class="p_numberedbullet"><span class="calibre10">This is after DEFINITION</span>, <span class="calibre10">these</span>. </p>
<p class="p_cat_heading">PRONUNCIATION </p>
<p class="p_numberedbullet"><span class="calibre10">This is after PRONUNCIATION</span>, <span class="calibre10">these</span>. </p>'''

from bs4 import BeautifulSoup

soup = BeautifulSoup(data, 'lxml')

s = soup.select_one('.p_cat_heading:contains("DEFINITION") + :not(.p_cat_heading)')
print(s.text)

印刷:

This is after DEFINITION, these. 

有幾種方法可以做到這一點,但是通過依賴 xpath 來完成大部分工作,這個表達式

//*[@class='p_cat_heading'][contains(text(),'DEFINITION')]/following-sibling::*[1]

應該管用。

使用 lxml:

from lxml import html

data = [your snippet above]
exp = "//*[@class='p_cat_heading'][contains(text(),'DEFINITION')]/following-sibling::*[1]"

tree = html.fromstring(data) 
target = tree.xpath(exp)

for i in target:
    print(i.text_content())

輸出:

這,這些。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM