Consulta XPath 'HTML Agility Pack' con AND lógico

c# html-agility-pack xpath

Pregunta

Estoy tratando de encontrar una tabla en un documento HTML con las primeras 2 filas que contienen 3 columnas con texto.

He experimentado tratando de usar la siguiente consulta, la cual quiero devolver el nodo que tiene las primeras 2 filas de la tabla que contiene texto en la primera columna:

string xpath = @"//table//table[//tr[1]//td[1]//*[contains(text(), *)] and //tr[2]//td[1]//*[contains(text(), *)]]";
HtmlNode temp = doc.DocumentNode.SelectSingleNode(xpath);

No funciona correctamente, mon.

Aquí hay una muestra de HTML, que es la tabla que estoy tratando de hacer coincidir:

    <table width="100%" cellpadding="0" border="0">
       <tbody>
       <tr>
          <td width="27%" valign="center"><b><font size="1" face="Helvetica">SOME TEXT<br></font></b></td>
          <td width="1%"></td>
          <td width="9%" valign="center"><font size="1" face="Helvetica">SOME TEXT<br></font></td>
          <td width="1%"></td>
          <td width="25%" valign="center"><font size="1" face="Helvetica">SOME TEXT<br></font></td>
          <td width="37%"></td>
       </tr>
       <tr>
          <td valign="center"><font size="1" face="Helvetica">SOME TEXT<br></font></td>
          <td></td>
          <td valign="center"><font size="1" face="Helvetica">1<br></font></td>
          <td></td>
          <td valign="center"><font size="1" face="Helvetica">SOME TEXT<br></font></td>
          <td></td>
       </tr>
       </tbody>
</table>

Observa que las columnas 1,3,5 tienen texto en las primeras 2 filas. Eso es lo que estoy tratando de hacer coincidir.

Respuesta aceptada

//table//table[//tr[1]//td[1]//*[contains(text(), *)] and //tr[2]//td[1]//*[contains(text(), *)]]

Hay muchos problemas con esta expresión XPath :

  1. //table//table selecciona cualquier table que sea descendiente de una table . Sin embargo, en el documento XML proporcionado no hay tablas anidadas.

  2. table[//tr[1]//td[1]//*[contains(text(), *)] . La //tr dentro del predicado es una expresión Xpath absoluta : selecciona todos los elementos tr en todo el documento , no solo en el subárbol arraigado por este elemento de table . Lo más probable es que quieras .//tr lugar de //tr .

  3. //td[1] selecciona cualquier elemento td que sea el primer hijo td de su padre, pero lo más probable es que solo desee el primer elemento td descendiente. Si es así, necesita usar esta expresión XPath: (//td)[1]

  4. //*[contains(text(), *)] esto selecciona cualquier elemento cuyo primer nodo de texto hijo contenga el valor de cadena del primer elemento hijo, pero simplemente desea verificar que un td tiene un nodo secundario de texto descendente - esto se puede seleccionar correctamente con: td[.//text()]

Combinando las correcciones de todos estos problemas, lo que probablemente desee es algo como :

  //table
     [(.//tr)[1]/td[1][.//text()]
    and
      (.//tr)[2]/td[1][.//text()]
     ]

Alternativamente, uno podría escribir una expresión equivalente pero más comprensible y menos propensa a errores como esta:

//table
  [descendant::tr[1]/td[1][descendant::text()]
 and
   descendant::tr[1]/td[1][descendant::text()]
  ]


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué