2012-05-14 9 views
15

Perché questo raccoglie tutti i miei elementi <li> nel mio documento?Agility Pack HTML, SelectNodes da un nodo

HtmlWeb web = new HtmlWeb(); 
HtmlDocument doc = web.Load(url); 

var travelList = new List<Page>(); 
var liOfTravels = doc.DocumentNode.SelectSingleNode("//div[@id='myTrips']") 
        .SelectNodes("//li"); 

Quello che voglio è quello di ottenere tutti gli elementi della <li><div> con un id di "myTrips".

risposta

15

È un po 'di confusione perché ci si aspetta che faccia un selectNodes solo sul div con id "myTrips", tuttavia se si esegue un altro SelectNodes ("// li") verrà eseguita un'altra ricerca dall'alto. del documento.

Ho risolto questo problema combinando l'istruzione in uno, ma ciò funzionava solo su una pagina Web in cui si dispone di un solo div con un ID "mytrips". La query sarà simile a questa:

doc.DocumentNode.SelectNodes ("// div [@ id = 'myTrips'] // li");

4

È possibile farlo con una query LINQ:

HtmlWeb web = new HtmlWeb(); 
HtmlDocument doc = web.Load(url); 

var travelList = new List<HtmlNode>(); 
foreach (var matchingDiv in doc.DocumentNode.DescendantNodes().Where(n=>n.Name == "div" && n.Id == "myTrips")) 
{ 
    travelList.AddRange(matchingDiv.DescendantNodes().Where(n=> n.Name == "li")); 
} 

Spero che aiuta

1

Questo sembra contro intuitivo mi entrava, se si esegue un metodo selectNodes su un nodo particolare ho pensato cercherebbe solo cose sotto quel nodo, non nel documento in generale.

OP se si modifica questa riga: var liOfTravels = doc.DocumentNode.SelectSingleNode ("// div [@ id = 'myTrips']"). SelectNodes ("// li");

TO: var liOfTravels = doc.DocumentNode.SelectSingleNode ("// div [@ id = 'myTrips']"). SelectNodes ("li");

Penso che starai bene, ho appena avuto lo stesso problema e quello lo ha risolto per me. Non sono sicuro se il li dovrebbe essere un figlio diretto del nodo che hai.

12
var liOfTravels = doc.DocumentNode.SelectSingleNode("//div[@id='myTrips']") 
       .SelectNodes(".//li"); 

Prendere nota del punto nella seconda riga. In pratica in questo senso HTMLAgitilityPack basa completamente sulla sintassi XPath, ma il risultato non è intuitivo, perché queste query sono effettivamente la stessa:

doc.DocumentNode.SelectNodes("//li"); 
some_deeper_node.SelectNodes("//li"); 
+0

Non credo che le query siano le stesse. In realtà quando esegue la prima selezione "// div [@ id = 'myTrips']" il nodo corrente cambia. Ecco perché la seconda selezione dovrebbe essere ".//li" (ovunque dal nodo corrente) e non "// li" (ovunque dalla radice). Agility fa esattamente ciò che ci si aspetta che faccia. – derloopkat

+0

@derloopkat, sono ** uguali (non c'è IMHO qui; se non lo fossero potevi rilasciare il punto nella query della soluzione, ma non puoi, puoi?). Sfortunatamente HTMLAgilityPack effettua ricerche dalla radice, indipendentemente dal nodo in cui ci si trova. La parte IMHO è questa: di solito il punto di concentrarsi su un dato nodo è che si continua la ricerca ** da ** quel nodo, non dalla radice di nuovo. La query della soluzione senza punto aggiunto nella seconda sotto-query non avrebbe alcun senso, quindi chiedete perché supportarli? – greenoldman

+0

Stiamo parlando di cose diverse. Quando ho detto che le domande non erano le stesse, stavo parlando di "// li" e ".//li". Con "quelle domande" rimandi alle domande di seguito. – derloopkat

5

Creazione di un nuovo nodo può essere utile in alcune situazioni e consente di utilizzare le XPaths più intuitivamente. Ho trovato questo utile in un paio di posti.

var myTripsDiv = doc.DocumentNode.SelectSingleNode("//div[@id='myTrips']"); 
var myTripsNode = HtmlNode.CreateNode(myTripsDiv.InnerHtml); 
var liOfTravels = myTripsNode.SelectNodes("//li"); 
Problemi correlati