2010-07-17 32 views
9

我正在使用Python + Selenium RC處理帶有css類「myclass」的可變數量的p元素的HTML頁面。如何迭代通過使用xpath匹配css類的DOM元素?

當我嘗試選擇與此XPath的每個節點:

//p[@class='myclass'][n] 

(與NA自然數)

我得到的只有每n該CSS類的第一個p元素,不同的情況如果我通過選擇與p元素迭代:

//p[n] 

有什麼辦法,我可以通過使用XPath的CSS類元素循環?

+0

好問題(+1)。請參閱我的答案,以獲取XPath表達式選擇的節點集中迭代的解釋和示例。 – 2010-07-17 16:35:38

+0

這個問題並不完全。你用什麼技術/語言來「處理」你的頁面?你想在XPath中「迭代」到底是什麼? (XPath是*選擇*語言,而不是*處理*語言。迭代作爲一個概念在這裏沒有多大意義。)請解釋一下。 – Tomalak 2010-07-17 16:54:12

+0

@Gj它可能有助於顯示嘗試迭代XPath表達式所選節點集的Python或Selenium RC代碼。 – LarsH 2010-09-13 16:44:25

回答

1

XPath 1.0不提供迭代構造

迭代可以在託管XPath的語言中對所選節點集執行。

實例

在XSLT 1.0

<xsl:for-each select="someExpressionSelectingNodes"> 
    <!-- Do something with the current node --> 
    </xsl:for-each> 

在C#

using System; 
using System.IO; 
using System.Xml; 

public class Sample { 

    public static void Main() { 

    XmlDocument doc = new XmlDocument(); 
    doc.Load("booksort.xml"); 

    XmlNodeList nodeList; 
    XmlNode root = doc.DocumentElement; 

    nodeList=root.SelectNodes("descendant::book[author/last-name='Austen']"); 

    //Change the price on the books. 
    foreach (XmlNode book in nodeList) 
    { 
     book.LastChild.InnerText="15.95"; 
    } 

    Console.WriteLine("Display the modified XML document...."); 
    doc.Save(Console.Out); 

    } 
} 

的XPath 2.0有它自己的iteration construct

for $varname1 in someExpression1, 
     $varname2 in someExpression2, 
     . . . . . . . . . . . 
     $varnameN in someExpressionN 
    return 
     SomeExpressionUsingTheVarsAbove 
+0

也許我的問題還不夠清楚,但我看不出你的答案與它有關。 我可以使用[n]結尾從多個簡單匹配中選擇一個元素,例如// p [n]遍歷所有p元素。我試圖迭代只有那些具有某個類的p元素時,我的問題就開始了。 – 2010-07-17 19:12:13

+0

誰低估了這個答案,請提出並說明原因?是因爲天氣不好還是因爲你是一個無能的懦夫?我想這是後者...... – 2010-07-17 23:05:31

+0

@GJ:爲什麼,只需從你的表達式中選擇someExpressionSelectingNodes('// p [@ class ='myclass'''')來選擇你要迭代的節點。我已經提供了兩個示例:如何組織迭代 - 使用兩種不同的託管語言。它必須是您使用的託管語言中類似的東西。 – 2010-07-17 23:52:30

0

也許你所有的這個類的div都在同一個級別,所以// p [@ class ='myclass']你會收到帶有指定類的段落數組。所以你應該使用索引遍歷它,例如 // p [@ class ='myclass'] [1],//p[@class='myclass'][2],...//p[@ class ='myclass'] [last()]

0

我不認爲你使用「索引」是因爲它的真正目的。在這個選擇中的//p[selection][index]語法實際上告訴你它的父應該是哪個元素......所以//p[selection][1]是說你選擇的p必須是它的父親的第一個孩子。 //p[selection][2]是說它必須是第二個孩子。根據你的html,這可能不是你想要的。

鑑於您使用的是Selenium和Python,有幾種方法可以做到您想要的,您可以查看this question以查看它們(這裏有兩個選項,一個用於selenium Javascript,另一個用於使用服務器端硒調用)。

+0

在XPath下,'[n]'謂詞(這是'[position()= n]'的簡稱)意思是「只選擇上下文組的第n個節點」。上下文組是由謂詞前面的XPath表達式指定的節點集合。這可能與也可能不涉及其在特定父母的兄弟姐妹中的順序。在這種情況下它沒有。 – LarsH 2010-09-13 16:40:53

+0

@LarsH - 是的,你有我......我無法解釋得那麼好。你是否同意鏈接的SO答案提供了正確的答案類型(也與Dimitre說的非常相似)......如果不是,我可能會刪除這個答案。 – Ryley 2010-09-13 18:54:39

+0

我不確定鏈接的答案是否相關。實際上,我似乎回想起我有限和很久以前的Selenium經驗,Selenium並不是真正的XPath,而是一個有限的子集,甚至可能不完全正確。所以這可能是OP的問題。就我所知,Selenium中的'[n]'按照你說的方式工作,而不是XPath規範說的方式。就像我在對問題的評論中所說的那樣,如果我們看到@Gj迭代的上下文,我們可能能夠解決問題。 – LarsH 2010-09-13 19:15:57

0

下面是一個C#代碼片段,可以幫助你。

這裏的關鍵是硒功能GetXpathCount()。它應該返回您正在查找的Xpath表達式的出現次數。

您可以在XPather或任何其他Xpath分析工具中輸入//p[@class='myclass'],以便確實可以驗證是否返回多個結果。然後你只需遍歷代碼中的結果。

就我而言,這是UL中所有需要迭代的列表項 - 即.e. //li[@class='myclass']/ul/li - 所以根據您的要求應該是這樣的:

int numProductsInLeftNav = Convert.ToInt32(selenium.GetXpathCount("//p[@class='myclass']")); 

List<string> productsInLeftNav = new List<string>(); 
for (int i = 1; i <= numProductsInLogOutLeftNav; i++) { 
    string productName = selenium.GetText("//p[@class='myclass'][" + i + "]"); 
    productsInLogoutLeftNav.Add(productName); 
} 
1

現在,我在這個問題再看看,我認爲真正的問題不是出在迭代,但在使用//

這是一個常見問題

//p[@class='myclass'][1] 

選擇具有class屬性具有值"myclass"p元件,這是它的父的第一個這樣的孩子。因此這個表達式可以選擇許多元素,其中沒有一個真的是文檔中的第一個這樣的元素p

當我們想要得到的第一p元素滿足上述謂詞文檔中,一個正確的表達是:

(//p)[@class='myclass'][1] 

記住:該[]操作具有更高的優先級(優先級),比//的縮寫。 無論您需要爲由//選擇的節點編制索引,始終要將表達式編入索引到括號中。

下面是一個示範

<nums> 
<a> 
    <n x="1"/> 
    <n x="2"/> 
    <n x="3"/> 
    <n x="4"/> 
</a> 
<b> 
    <n x="5"/> 
    <n x="6"/> 
    <n x="7"/> 
    <n x="8"/> 
</b> 
</nums> 

XPath表達式

//n[@x mod 2 = 0][1] 

選擇以下節點

<n x="2" /> 
<n x="6" /> 

XPath表達式

(//n)[@x mod 2 = 0][1] 

選擇完全相同的第一n元件在文檔中與想要的屬性:

<n x="2" /> 

嘗試此第一與下列變換

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/"> 
    <xsl:copy-of select="//n[@x mod 2 = 0][1]"/> 
</xsl:template> 
</xsl:stylesheet> 

並且結果是兩個節點

<n x="2" /> 
<n x="6" /> 

現在,改變XPath表達式如下,然後再試一次

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/"> 
    <xsl:copy-of select="(//n)[@x mod 2 = 0][1]"/> 
</xsl:template> 
</xsl:stylesheet> 

,其結果是我們真正想要 - 文檔中的第一個這樣的n元素:

<n x="2" />