parser parse htmlagilitypack example agility c# xpath html-agility-pack

c# - parse - HtmlAgilityPack y seleccionando Nodos y Subnodos



htmlagilitypack load url (5)

Espero que alguien pueda ayudarme.

Digamos que tengo un documento html que contiene varios divs como este ejemplo:

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

Estoy usando HtmlAgilityPack para obtener el documento html. Lo que necesito saber es cómo puedo obtener los tramos para cada "search_hit" -div?

Mi primer pensamiento fue algo como esto:

foreach (HtmlAgilityPack.HtmlNode node in doc.DocumentNode.SelectNodes("//div[@class=''search_hit'']")) { foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("//span[@prop]")) { } }

Cada div debe ser un objeto con los tramos incluidos como propiedades. I. e.

public class Record { public string Name { get; set; } public string company { get; set; } public string street { get; set; } }

Y esta lista se completará luego:

public List<Record> Results = new List<Record>();

Pero el XPATH que uso no está haciendo una búsqueda en el subnodo como debería. Parece que busca todo el documento una y otra vez.

Quiero decir que ya lo hice funcionar de esa manera que solo obtuve los tramos de toda la página. Pero entonces no tengo ninguna relación entre los tramos y divs. Significa: ya no sé qué extensión está relacionada con qué div.

¿Alguien sabe una solución? Ya jugué tanto que estoy totalmente confundido ahora :)

¡Cualquier ayuda es apreciada!


Antes que nada, eche un vistazo a esto: Html Agility Pack - Subnode de selección de problemas

Aquí hay una solución de trabajo completa para su pregunta:

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); }

Si lees la pregunta que te ./span[@prop=''name''] verás que hacer ./span[@prop=''name''] es exactamente igual, ya que esos nodos de span son hijos (directos) del nodo div .

Si los nodos del compás no tienen esos atributos del atributo, y desea asignarlos según el orden en que aparecen, puede hacer:

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); }


El siguiente funciona para mi. El bit importante es justo como BeniBela señaló agregar un punto en la segunda llamada a ''SeleccionarNodos''.

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); }


Me avergüenza :)

Todos ustedes tenían razón.

Encontré el problema. Esta NullReferenceException no dejaba de molestarme, así que pasé más tiempo para verla en detalle. Entre todos los divs había un div con el mismo atributo "class = ''search-hit''" pero sin los espacios interiores. Por eso atraviesa un error en el segundo ciclo.

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); }

El código de arriba está funcionando.

¡Gracias a todos por su tiempo y ayuda!


Si usa // , busca desde el documento comenzar.

Use .// para buscar todo desde el nodo actual

foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes(".//span[@prop]"))

O suelte el prefijo por completo para buscar solo para niños directos:

foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("span[@prop]"))


Yo usé eso. ID de conversión de clase

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); }