Voici l'exemple de code HTML que j'essaie d'analyser avec Html Agility Pack dans ASP.Net (C #).
<div class="content-div">
<dl>
<dt>
<b><a href="1.html" title="1">1</a></b>
</dt>
<dd> First Entry</dd>
<dt>
<b><a href="2.html" title="2">2</a></b>
</dt>
<dd> Second Entry</dd>
<dt>
<b><a href="3.html" title="3">3</a></b>
</dt>
<dd> Third Entry</dd>
</dl>
</div>
Les valeurs que je veux sont:
(J'ai pris des exemples de la première entrée ici mais je veux les valeurs de ces éléments pour toutes les entrées de la liste)
C'est le code que j'utilise actuellement,
var webGet = new HtmlWeb();
var document = webGet.Load(url2);
var parsedValues=
from info in document.DocumentNode.SelectNodes("//div[@class='content-div']")
from content in info.SelectNodes("dl//dd")
from link in info.SelectNodes("dl//dt/b/a")
.Where(x => x.Attributes.Contains("href"))
select new
{
Text = content.InnerText,
Url = link.Attributes["href"].Value,
AnchorText = link.InnerText,
};
GridView1.DataSource = parsedValues;
GridView1.DataBind();
Le problème, c’est que j’obtiens correctement les valeurs du lien et du texte d’ancrage, mais que le texte interne ne prend que la valeur de la première entrée et remplit la même valeur pour toutes les autres entrées pour le nombre total de fois où puis on recommence avec le second. Je ne suis peut-être pas aussi clair dans mon explication, voici donc un exemple de résultat obtenu avec ce code:
First Entry 1.html 1
First Entry 2.html 2
First Entry 3.html 3
Second Entry 1.html 1
Second Entry 2.html 2
Second Entry 3.html 3
Third Entry 1.html 1
Third Entry 2.html 2
Third Entry 3.html 3
Alors que j'essaie d'obtenir
First Entry 1.html 1
Second Entry 2.html 2
Third Entry 3.html 3
Je suis un nouveau venu chez HAP et je connais très peu de choses sur xpath. Je suis donc certain que je ne fais pas quelque chose de mal ici, mais je ne pouvais pas le faire fonctionner même après y avoir passé des heures. Toute aide serait très appréciée.
Solution 1
J'ai défini une fonction qui donne un dt
nœud retourne le suivant dd
noeud après:
private static HtmlNode GetNextDDSibling(HtmlNode dtElement)
{
var currentNode = dtElement;
while (currentNode != null)
{
currentNode = currentNode.NextSibling;
if(currentNode.NodeType == HtmlNodeType.Element && currentNode.Name =="dd")
return currentNode;
}
return null;
}
et maintenant le code LINQ peut être transformé en:
var parsedValues =
from info in document.DocumentNode.SelectNodes("//div[@class='content-div']")
from dtElement in info.SelectNodes("dl/dt")
let link = dtElement.SelectSingleNode("b/a[@href]")
let ddElement = GetNextDDSibling(dtElement)
where link != null && ddElement != null
select new
{
Text = ddElement.InnerHtml,
Url = link.GetAttributeValue("href", ""),
AnchorText = link.InnerText
};
Solution 2
Sans fonctions supplémentaires:
var infoNode =
document.DocumentNode.SelectSingleNode("//div[@class='content-div']");
var dts = infoNode.SelectNodes("dl/dt");
var dds = infoNode.SelectNodes("dl/dd");
var parsedValues = dts.Zip(dds,
(dt, dd) => new
{
Text = dd.InnerHtml,
Url = dt.SelectSingleNode("b/a[@href]").GetAttributeValue("href", ""),
AnchorText = dt.SelectSingleNode("b/a[@href]").InnerText
});
Par exemple, comment analyser certains éléments en utilisant Html Agility Pack
public string ParseHtml()
{
string output = null;
HtmlDocument htmldocument = new HtmlDocument();
htmldocument.LoadHtml(YourHTML);
HtmlNode node = htmldocument.DocumentNode;
HtmlNodeCollection dds = node.SelectNodes("//dd"); //Select all dd tags
HtmlNodeCollection anchors = node.SelectNodes("//b/a[@href]"); //Select all 'a' tags that contais href attribute
for (int i = 0; i < dds.Count; i++)
{
string atributteValue = null.
Text = dds[i].InnerText;
Url = anchors[i].GetAttributeValue("href", atributteValue);
AnchorText = anchors[i].InnerText;
//Your code...
}
return output;
}