html
  • css
  • selenium-rc
  • xpath
  • 2010-07-17 32 views 9 likes 
    9

    Estoy procesando una página HTML con un número variable de elementos p con una clase css "myclass", usando Python + Selenium RC.¿Cómo iterar a través de los elementos DOM que coinciden con una clase css utilizando xpath?

    Cuando intento para seleccionar cada nodo con este XPath:

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

    (con na número natural)

    consigo sólo el primer elemento p con esta clase CSS para cada n, a diferencia de la situación si iterar a través de la selección de todos los elementos p con:

    //p[n] 
    

    ¿hay alguna manera de iterar a través de elementos de clase CSS utilizando XPath?

    +0

    Buena pregunta (+1). Consulte mi respuesta para obtener una explicación y un ejemplo de iteración en un conjunto de nodos seleccionado por una expresión XPath. –

    +0

    La pregunta no está realmente completa. ¿Qué tecnología/lenguaje estás usando para "procesar" tu página? ¿Qué es exactamente lo que quieres "iterar" en XPath? (XPath es un lenguaje de * selección *, no un lenguaje de * procesamiento *. La iteración como concepto no significa mucho aquí.) Explique. – Tomalak

    +0

    @Gj puede ser útil mostrar el código Python o Selenium RC que intenta iterar a través del conjunto de nodos seleccionado por la expresión XPath. – LarsH

    Respuesta

    1

    XPath 1.0 no proporciona una construcción iterativa.

    La iteración se puede realizar en el conjunto de nodos seleccionado en el idioma que aloja XPath.

    Ejemplos:

    En XSLT 1.0:

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

    en 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 tiene su propio iteration construct:

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

    tal vez mi pregunta no era lo suficientemente clara, pero no puedo ver cómo su respuesta está relacionada con ella. Puedo usar la terminación [n] para seleccionar un elemento de varias coincidencias simples, p. Ej. // p [n] para iterar a través de TODOS los p elementos. mi problema comienza cuando intento iterar solo aquellos elementos p que tienen cierta clase. –

    +0

    Quien haya votado negativamente esta respuesta, por favor, indique las razones? ¿fue por mal tiempo o por el hecho de que eres un cobarde incompetente? Supongo que fue este último ... –

    +0

    @Gj: Por qué, simplemente sustituye someExpressionSelectingNodes de mi respuesta con tu expresión ('// p [@ class = 'myclass']') que selecciona los nodos por los que deseas iterar. He proporcionado dos ejemplos de cómo se organiza la iteración: en dos idiomas de alojamiento diferentes. Tiene que ser algo similar en el lenguaje de alojamiento que está utilizando. –

    0

    Tal vez todas sus divs con esta clase se encuentran en el mismo nivel, por lo que por // p [@ class = 'miclase'] que recibe el conjunto de párrafos con la clase especificada. Por lo tanto, debe recorrerlo utilizando índices, es decir, // p [@ class = 'myclass'] [1], //p[@class='myclass'][2],...,//p[@ class = 'myclass'] [last()]

    0

    No creo que esté utilizando el "índice" por su verdadero propósito. La sintaxis //p[selection][index] en esta selección realmente le dice qué elemento dentro de su elemento primario debería ser ... Por lo tanto, //p[selection][1] está diciendo que su p seleccionada debe ser la primera hija de su elemento principal. //p[selection][2] dice que debe ser el segundo hijo. Dependiendo de tu html, es probable que esto no sea lo que quieres.

    Teniendo en cuenta que usted está utilizando selenio y Python, hay un par de maneras de hacer lo que quiere, y se puede ver en this question verlos (hay dos opciones que se ofrecen allí, uno en selenio Javascript, y el otro con el llamadas de selenio del lado del servidor).

    +0

    En XPath, el predicado '[n]' (que es la abreviatura de '[position() = n]') significa "seleccionar solo el' n'th nodo del grupo de contexto ". El grupo de contexto es el conjunto de nodos especificado por la expresión XPath que precede al predicado. Esto puede o no estar relacionado con su orden entre los hermanos de un padre en particular. En este caso, no. – LarsH

    +0

    @LarsH - Sí, me tienes ... No fui capaz de explicar eso para nada. ¿Está de acuerdo con que las respuestas de SO vinculadas sugieran el tipo correcto de respuesta (también muy similar a lo que dice Dimitre) ... si no, probablemente elimine esta respuesta. – Ryley

    +0

    No estoy seguro de si las respuestas vinculadas son relevantes. En realidad, me parece recordar, a partir de mi experiencia limitada y antigua de Selenium, que el Selenium no tiene XPath real, sino un subconjunto limitado e incluso entonces puede no ser del todo correcto. Así que ese podría haber sido el problema del OP. Por lo que sé, '[n]' en Selenium funciona de la forma en que dijiste en lugar de hacerlo de la forma en que lo dice XPath. Como dije en mi comentario sobre la pregunta, si viéramos el contexto donde @Gj se está iterando, podríamos ser capaces de resolver el problema. – LarsH

    0

    Aquí hay un fragmento de código de C# que podría ayudarlo.

    La clave aquí es la función Selenium GetXpathCount(). Debería devolver el número de apariciones de la expresión Xpath que está buscando.

    Puede ingresar //p[@class='myclass'] en XPather o en cualquier otra herramienta de análisis de Xpath para que pueda verificar la obtención de resultados múltiples. Luego solo itera a través de los resultados en tu código.

    En mi caso, eran todos los elementos de la lista en una UL que necesitaban ser iterados -i.e. //li[@class='myclass']/ul/li - por lo que en función de sus necesidades debe ser algo como:

    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

    Ahora que miro de nuevo a esta pregunta, creo que el verdadero problema no está en la iteración , pero en el uso de //.

    Este es un FAQ:

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

    selecciona cadap elemento que tiene un atributo con el valor class"myclass" y que es el primero de estos hijo de su padre. Por lo tanto, esta expresión puede seleccionar muchos elementos p, ninguno de los cuales es realmente el primer elemento p en el documento.

    Cuando queremos conseguir el primer p elemento en el documento que satisfaga el predicado anteriormente, una expresión correcta es:

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

    Recuerde: El operador [] tiene mayor prioridad (precedencia) que la // abreviatura. Cuando necesite indexar los nodos seleccionados por //, coloque siempre la expresión entre los paréntesis.

    Aquí es una demostración:

    <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> 
    

    La expresión XPath:

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

    selecciona los siguientes dos nodos:

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

    La expresión XPath:

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

    selecciona exactamente el primer n elemento en el documento con la propiedad deseada:

    <n x="2" /> 
    

    probar este primero con la siguiente transformación:

    <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> 
    

    y el resultado son dos nodos.

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

    Ahora, cambiar la expresión XPath que a continuación y vuelve a intentarlo:

    <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> 
    

    y el resultado es lo que realmente queríamos - la primera n elemento en el documento:

    <n x="2" /> 
    
    Cuestiones relacionadas