XPath / HtmlAgilityPack: как найти элемент (a) с определенным значением для атрибута (href) и найти соседние столбцы таблицы?

Я в отчаянии, потому что не могу понять, как достичь того, что я сказал в вопросе. Я уже читал бесчисленное количество подобных примеров, но не нашел того, который работает в точной ситуации. Итак, предположим, у меня есть следующий код:

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

теперь то, что у меня уже есть, является частью url-a. Я в основном хочу знать, как я могу получить id A и img A. Я пытаюсь "найти" линию с XPath, но я не могу придумать способ заставить ее работать. Кроме того, возможно, что информации нет вообще. Это моя последняя попытка (серьезно, я возился с этим более 3 часов, пытаясь различными способами):

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;

Ну, это, по-видимому, неправильно, так что я был бы очень рад, если бы кто-то мог мне помочь здесь. Также я был бы признателен, если бы кто-то мог указать мне на какой-то сайт, который подробно объясняет XPath и обозначения/синтаксис с примерами, подобными этому. Книги также приветствуются.

PS: Я знаю, что мог бы достичь своей цели без XPath вообще тоже с регулярным выражением или просто простым StreamReader в C# и проверкой, содержит ли каждая строка то, что мне нужно, но а) это слишком хрупко для моих нужд, потому что код может иметь резкие разрывы строк и б) я действительно хочу остаться consistend с полностью придерживаться XPath для всего, что я делаю в этом проекте.

заранее спасибо за вашу помощь!

2 ответов


используйте следующие выражения XPath:

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

при оценке по предоставленному (искаженному, но исправленному) XML-документу:

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

выбран нужный текстовый узел:

id A

аналогично, это выражение XPath:

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

при оценке по тому же XML-документу (выше), выбирает другой нужный текст узел:

img A

проверка на основе XSLT:

когда это преобразование применяется к XML-документу (выше):

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

желаемые результаты получены:

id A
img A

у вас есть серьезно сломанный HTML с unmatching закрытия td теги. Исправьте их, пожалуйста. Это просто уродливая картинка.

это, как говорится, надеюсь, HTML Agility Pack может обрабатывать любое дерьмо, которое вы бросаете на него, так что вот как действовать и анализировать мусор, который у вас есть, и найти id и img значения с учетом 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);
                }
            }
        }
    }
}