Htmlagilipack i wybieranie węzłów i Podmodułów
Mam nadzieję, że ktoś mi pomoże.
Powiedzmy, że mam dokument html, który zawiera wiele div, jak w tym przykładzie:
<div class="search_hit">
<span prop="name">Richard Winchester</span>
<span prop="company">Kodak</span>
<span prop="street">Arlington Road 1</span>
</div>
<div class="search_hit">
<span prop="name">Ted Mosby</span>
<span prop="company">HP</span>
<span prop="street">Arlington Road 2</span>
</div>
Im za pomocą HtmlAgilityPack, aby uzyskać dokument html. Co muszę wiedzieć, jak Mogę uzyskać zakresy dla każdego "search_hit" - div?
Moja pierwsza myśl była taka:
foreach (HtmlAgilityPack.HtmlNode node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']"))
{
foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("//span[@prop]"))
{
}
}
Każdy div powinien być obiektem z dołączonymi zakresami jako właściwościami. I. E.
public class Record
{
public string Name { get; set; }
public string company { get; set; }
public string street { get; set; }
}
I listę tę wypełnia się wtedy:
public List<Record> Results = new List<Record>();
Ale XPATH im za pomocą nie robi wyszukiwania w podnodzie, jak powinno to zrobić. Szwy, że przeszukuje cały dokument ponownie i ponownie.
Mam na myśli, że już to działa w ten sposób, że po prostu uzyskać przęsła całej strony. Ale wtedy nie mam związku między przęsłami i divami. Znaczy: Nie wiem już, który zakres jest związany z którym div.
Czy ktoś zna jakieś rozwiązanie? Grałem już tyle, że jestem teraz całkowicie zdezorientowany:)Każda pomoc jest doceniam to!
5 answers
Poniżej działa dla mnie. Ważnym bitem jest tak jak zauważył BeniBela dodanie kropki w drugim wywołaniu do 'SelectNodes'.
List<Record> lstRecords=new List<Record>();
foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']"))
{
Record record=new Record();
foreach (HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
{
string attributeValue = node2.GetAttributeValue("prop", "");
if (attributeValue == "name")
{
record.Name = node2.InnerText;
}
else if (attributeValue == "company")
{
record.company = node2.InnerText;
}
else if (attributeValue == "street")
{
record.street = node2.InnerText;
}
}
lstRecords.Add(record);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-21 23:06:38
Jeśli używasz //
, przeszukuje od początku dokumentu.
Użyj .//
, aby przeszukać wszystkie z bieżącego węzła
foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
Lub porzuć przedrostek całkowicie, aby wyszukać tylko bezpośrednie dzieci:
foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("span[@prop]"))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-21 13:55:06
Po pierwsze, spójrz na to: Html Agility Pack-Problem z wyborem podnodu
Oto pełne rozwiązanie dla Twojego pytania:
IList<Record> results = new List<Record>();
foreach (var node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']")) {
var record = new Record();
record.Name = node.SelectSingleNode(".//span[@prop='name']").InnerText;
record.company = node.SelectSingleNode(".//span[@prop='company']").InnerText;
record.street = node.SelectSingleNode(".//span[@prop='street']").InnerText;
results.Add(record);
}
Jeśli przeczytasz pytanie, na które Ci zwróciłem uwagę, zobaczysz, że robienie ./span[@prop='name']
jest dokładnie takie samo, ponieważ te span
węzły są (bezpośrednimi) dziećmi div
węzła.
Jeśli span
węzły nie mają atrybutów prop
i chcesz je przypisać w zależności od kolejności, w jakiej się pojawiają, możesz do:
foreach (var node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']")) {
var spanNodes = node.SelectNodes("./span");
var record = new Record();
record.Name = spanNodes[0].InnerText;
record.company = spanNodes[1].InnerText;
record.street = spanNodes[2].InnerText;
results.Add(record);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:09
Wstyd mi:)
Wszyscy mieliście rację. Znalazłem problem. Ta NullReferenceException dokuczała mi, więc spędziłem więcej czasu, aby przyjrzeć się jej szczegółowo. Pomiędzy tymi divami był jeden div z tym samym atrybutem "class=' search-hit'", ale bez przęseł wewnątrz. Dlatego przechodzi błąd w drugiej pętli.foreach (HtmlAgilityPack.HtmlNode node in doc.DocumentNode.SelectNodes("//span[@prop]/ancestor::div[@class='search_hit']"))
{
Record rec = new Record();
foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
{
}
rList.Results.Add(rec);
}
Powyższy kod działa.
Dziękuję wam za Wasz czas i pomoc!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-22 12:47:08
Użyłem tego. class convert id
HtmlNodeCollection nodes = dokuman.DocumentNode.SelectNodes("//div[@id='search_hit']//span[@prop]");
for (int i = 0; i < nodes .Count; i++)
{
var record = new Record();
record.Name = links[i].InnerText; results.Add(record); }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-14 07:54:24