2011-01-06 59 views
30

正如在此Stack Overflow answer中想象的那樣,您需要選擇一個特定的表格,然後選擇它的所有行。由於HTML的放縱,所有三個以下是合法的標記:具有可選元素的層次結構的XPath

<table id="foo"><tr>...</tr></table> 
<table id="foo"><tbody><tr>...</tr></tbody></table> 
<table id="foo"><tr>...</tr><tbody><tr>...</tr></tbody></table> 

你擔心嵌套表的表,所以不想使用XPath像
table[@id="foo"]//tr

如果你可以指定所需的XPath作爲一個正則表達式,它可能看起來像:
table[@id="foo"](/tbody)?/tr

在一般情況下,你怎麼可以指定一個XPath表達式,它允許在選擇的層次結構中的可選元素?

要說清楚,我並不是想解決真實世界的問題,或者選擇特定文檔的特定元素。我正在尋求解決一類問題的技巧。

+0

哦,爲了簡單和通用的緣故,我忽略了`thead`和`tfoot`元素HTML法律。 – Phrogz 2011-01-06 03:30:54

回答

19

我不明白爲什麼你不能使用此:

//table[@id='foo']/tr|//table[@id='foo']/tbody/tr 

如果不想節點並集一個表達:

//tr[(.|parent::tbody)[1]/parent::table[@id='foo']] 
7

使用

//table[@id="foo"]/*[self::tbody or self::thead or self::tfoot]/tr 
    | 
    //table[@id="foo"]/tr 

選擇任何tr元素是具有id屬性「富」或任何tr元素是tbody的孩子是一個孩子的任何table的孩子任何table

+0

我很欣賞你在這方面的專業知識,但是這真的是最好的可以做到的嗎?如果xpath的第一部分和最後一部分只是「table」和「tr」,這並不算太壞,但是像`div [@ id =「contents] // table [@ class =」comments「](/tbody)?/ tr/[td // text()[contains(。,'targetString')]]`它變得非常[DRY](http://en.wikipedia.org/wiki/Don't_repeat_yourself )來複制一個變體的表達式 – Phrogz 2011-01-06 03:56:52

+0

@Progro:不,它幾乎和我的初始表達式一樣簡單 - 請參閱編輯。它可以在XPath 2.0中更加優雅,並且在XML文檔中更加優雅一個已知的XML模式(在XHTML中就是這種情況) – 2011-01-06 05:38:14

+0

什麼是更優雅的XPath 2.0版本?我能找到的最好的是一個交替的步驟「。「和可選部分。對於TEI上的Saxon,這適用於我:/TEI.2/text/(.|group/text)/body/div1 – 2013-01-29 20:43:55

3

在XPath 2.0,可選步驟可以表示爲(tbody|.)

//table[@id="foo"]/(tbody|.)/tr 

XPathTester.com demo

管道(|)表示union(兩個節點套),dot.)表示身份的步驟(返回正是上一步中所做的那樣)。

這可以擴大一次,包括多個可選元素:

//table[@id="foo"]/(thead|tbody|tfoot|.)/tr 
相關問題