HtmlAgilityPack выбирает данные из под-узла

c# html html-agility-pack linq parsing

Вопрос

У меня есть следующий код HTML, который я бы хотел проанализировать:

<h3 class='bar'>
  <a href='http://anysite.com/index.php?showuser=7195' title='Profile view'>THIS_IS_USERNAME</a>
  &nbsp;
  <a href='http://anysite.com/index.php?showuser=7195&amp;f=' class='__user __id7195' title='Profile view'>
      <img src='http://anysite.com/public/style_images/car/user_popup.png' alt='' />
   </a>
</h3>

Здесь мне нужно выбрать имя пользователя («THIS_IS_USERNAME») и ссылку на профиль (« http://anysite.com/index.php?showuser=7195 »)

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

List<HtmlNode> resultSearch = HTMLPage.DocumentNode.Descendants()
                .Where(
                         x => x.Name.Equals("h3")
                         && x.Attributes["class"] != null
                         && x.Attributes["class"].Value.Equals("bar")                         
                      )
                .ToList();

Но как я могу получить не сам узел «h3», а «а» внутри «h3» с этой ссылкой атрибутов, которая содержит имя пользователя и ссылку на профиль, который мне нужен?

Принятый ответ

Вы можете напрямую запросить узел ссылки, он довольно отличается от атрибута Title на нем.

В этом случае использование XPath, вероятно, проще, поскольку оно обрабатывает все промежуточные проверки на нуль, и оно просто безопасно для типов, так как ваш запрос Linq будет содержать много постоянных строк:

var node = HTMLPage.DocumentNode.SelectSingleNode("//hr[@class='Bar']/a[@title='Profile View' and @href");
if (node != null)
{
    string link = node.Attributes["href"].Value;
    string username = node.InnerText;
}

Вы можете написать аналогичный код с помощью синтаксиса Linq, он сначала ищет тег ссылки, а затем обратный путь, чтобы найти родительский элемент h3 для него. Таким образом, вам не нужно проверять промежуточные нули;):

var node = HtmlPage.DocumentNode.Descendants("a")
    .Where(a =>
        a.Ascendants("h3")
            .Any(h3 =>
                h3.Attributes["class"] != null 
                && a.Attributes["class"].Value == "bar"
            )
    )
    .Where(a => 
        a.Attributes["title"] != null 
        && a.Attributes["title"].Value == "Profile View"
        && a.Attributes["href"] != null
    )
    .FirstOrDefault();

if (node != null)
{
    string link = node.Attributes["href"].value;
    string username = node.InnerText;
}

Или вы можете использовать его положение как первый <a> дочерний <a> "bar":

// the call to First() will throw an exception if the h3 isn't found.
// returning an empty HtmlNode will allow you to ignore that

var node = (HtmlPage.DocumentNode.Descendants("h3")
    .FirstOrDefault( h => 
            h3.Attributes["class"] != null 
            && a.Attributes["class"].Value == "bar")
    ) ?? HtmlPage.CreateElement("h3")) 
    .Elements("a").FirstOrDefault();

if (node != null)
{
    string link = node.Attributes["href"].value;
    string username = node.InnerText;
}


Related

Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow