XPath / HtmlAgilityPack: ¿Cómo encontrar un elemento (a) con un valor específico para un atributo (href) y encontrar columnas de tablas adyacentes?

c# html html-agility-pack visual-studio xpath

Pregunta

Estoy bastante desesperado porque no puedo imaginar cómo lograr lo que dije en la pregunta. Ya he leído innumerables ejemplos similares pero no encontré uno que funcione en una situación exacta. Entonces, digamos que tengo el siguiente código:

<table><tr>
<td><a href="url-a">text A</a></td><td><a>id A</a></td><td><a>img A</a></td>
<td><a href="url-b">text B</a></td><td><a>id B</a></td><td><a>img B</a></td>
<td><a href="url-c">text C</a></td><td><a>id C</a></td><td><a>img C</a></td>
</tr></table>

Ahora, lo que ya tengo es una parte de url-a. Básicamente, quiero saber cómo puedo obtener la identificación A y la imagen A. Estoy tratando de "encontrar" la línea con XPath pero no puedo encontrar una manera de hacer que funcione. Además, podría ser posible que la información no esté presente en absoluto. Este es mi último intento (en serio, he jugado con esto durante más de 3 horas probando varias maneras diferentes):

if (htmlDoc.DocumentNode.SelectSingleNode(@"/a[contains(@href, 'part-url-a')]") != null)
    string ida = htmlDoc.DocumentNode.SelectSingleNode(@"/a[contains(@href, 'part-url-a')]/following-sibling::a").InnerText;

Bueno, aparentemente está mal como el infierno, así que estaría muy contento si alguien pudiera ayudarme aquí. También agradecería que alguien me indicara algún sitio web que explique XPath y las notaciones / sintaxis en detalle con ejemplos como este. Los libros también son bienvenidos.

PD: Sé que podría lograr mi objetivo sin XPath en absoluto con Regex o solo con un StreamReader simple en C # y comprobar si cada línea contiene lo que necesito, pero a) es demasiado frágil para mis necesidades porque el código podría tener saltos de línea abruptos y b) Tengo muchas ganas de mantener la coherencia con el apego total a XPath para cualquier cosa que esté haciendo en este proyecto.

¡Gracias de antemano por tu ayuda!

Respuesta aceptada

Usa las siguientes expresiones XPath :

   /*/tr/td[a[@href='url-a']]
                /following-sibling::td[1]
                     /a/text()

Cuando se evalúa contra el documento XML proporcionado (con formato incorrecto pero corregido) :

<table><tr>
<td><a href="url-a">text A</a></td><td><a>id A</a></td><td><a>img A</a></td>
<td><a href="url-b">text B</a></td><td><a>id B</a></td><td><a>img B</a></td>
<td><a href="url-c">text C</a></td><td><a>id C</a></td><td><a>img C</a></td>
</tr></table>

Se selecciona el nodo de texto deseado :

id A

Del mismo modo, esta expresión XPath :

   /*/tr/td[a[@href='url-a']]
                /following-sibling::td[2]
                     /a/text()

cuando se evalúa contra el mismo documento XML (arriba), selecciona el otro nodo de texto deseado :

img A

Verificación basada en XSLT :

Cuando esta transformación se aplica en el documento XML (arriba):

<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=
   "/*/tr/td[a[@href='url-a']]
                /following-sibling::td[1]
                     /a/text()"/>

  <xsl:text>&#10;</xsl:text>
  <xsl:copy-of select=
   "/*/tr/td[a[@href='url-a']]
                /following-sibling::td[2]
                     /a/text()"/>
 </xsl:template>
</xsl:stylesheet>

Se producen los resultados deseados :

id A
img A

Respuesta popular

Usted tiene un HTML seriamente roto con etiquetas de td cierre incomparables. Arreglalos por favor. Es solo una imagen fea de esta marca.

Dicho esto, con suerte, Html Agility Pack puede manejar cualquier basura que le lances, así que aquí tienes cómo proceder y analizar la basura que tienes y encontrar los valores de id e img dados el href :

class Program
{
    static void Main()
    {
        var doc = new HtmlDocument();
        doc.Load("test.html");
        var anchor = doc.DocumentNode.SelectSingleNode("//a[contains(@href, 'url-a')]");
        if (anchor != null)
        {
            var id = anchor.ParentNode.SelectSingleNode("following-sibling::td/a");
            if (id != null)
            {
                Console.WriteLine(id.InnerHtml);
                var img = id.ParentNode.SelectSingleNode("following-sibling::td/a");
                if (img != null)
                {
                    Console.WriteLine(img.InnerHtml);
                }
            }
        }
    }
}


Related

Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow