2010-07-17 67 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" />