2012-05-14 35 views
15

Tại sao điều này chọn tất cả các phần tử <li> trong tài liệu của tôi?Gói Agility Html, SelectNodes từ nút

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

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

Những gì tôi muốn là để có được tất cả các yếu tố trong <li><div> với một id của "myTrips".

Trả lời

15

Hơi khó hiểu vì bạn đang mong đợi rằng nó sẽ thực hiện một nút chọn chỉ trên div có id "myTrips", tuy nhiên nếu bạn thực hiện một SelectNodes khác ("// li") nó sẽ thực hiện một tìm kiếm khác từ trên cùng của tài liệu.

Tôi đã sửa lỗi này bằng cách kết hợp câu lệnh thành một, nhưng điều đó sẽ chỉ hoạt động trên trang web mà bạn chỉ có một div có id "mytrips". Truy vấn sẽ trông giống như sau:

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

4

Bạn có thể làm điều này với một truy vấn 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")); 
} 

Tôi hy vọng nó giúp

1

Điều này có vẻ phản trực quan đối với tôi là tốt, nếu bạn chạy một phương pháp SelectNodes trên một nút đặc biệt tôi nghĩ nó sẽ chỉ tìm kiếm nội dung bên dưới nút đó, chứ không phải trong tài liệu nói chung.

Dù sao OP nếu bạn thay đổi dòng này: var liOfTravels = doc.DocumentNode.SelectSingleNode ("// div [@ id = 'myTrips']"). SelectNodes ("// li");

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

Tôi nghĩ bạn sẽ ổn, tôi vừa gặp sự cố tương tự và đã khắc phục sự cố đó cho tôi. Im không chắc chắn mặc dù nếu li sẽ phải là một con trực tiếp của nút bạn có.

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

Lưu ý dấu chấm trong dòng thứ hai. Về cơ bản trong vấn đề này HTMLAgitilityPack hoàn toàn dựa vào cú pháp XPath, tuy nhiên kết quả là không trực quan, bởi vì những truy vấn là một cách hiệu quả như nhau:

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

Tôi không nghĩ rằng các truy vấn giống nhau. Trên thực tế, khi anh ta chọn "// div [@ id = 'myTrips'] đầu tiên" thì nút hiện tại sẽ thay đổi. Đó là lý do tại sao lựa chọn thứ hai nên là ".//li" (bất kỳ nơi nào từ nút hiện tại) và không phải "// li" (ở bất kỳ đâu từ gốc). Agility thực hiện chính xác những gì được mong đợi sẽ làm. – derloopkat

+0

@derloopkat, chúng ** là giống nhau (không có IMHO ở đây; nếu chúng không phải là bạn có thể thả dấu chấm trong truy vấn giải pháp, nhưng bạn không thể, có thể không?). Thật không may HTMLAgilityPack tìm kiếm từ gốc, không có vấn đề gì bạn đang ở nút. Phần IMHO là điều này - thường là điểm tập trung vào nút nhất định là bạn tiếp tục tìm kiếm ** từ ** nút đó, không phải từ gốc một lần nữa. Truy vấn giải pháp mà không có dấu chấm được thêm vào trong truy vấn phụ thứ hai sẽ không có ý nghĩa gì cả, do đó đặt câu hỏi tại sao hỗ trợ chúng? – greenoldman

+0

Chúng ta đang nói về những thứ khác nhau. Khi tôi nói các truy vấn không giống nhau, tôi đã nói về "// li" và ".//li". Bởi "những truy vấn", bạn tham khảo các truy vấn dưới đây. – derloopkat

5

Tạo một nút mới có thể mang lại lợi ích trong một số trường hợp và cho phép bạn sử dụng XPath trực quan hơn. Tôi đã thấy điều này hữu ích ở một vài nơi.

var myTripsDiv = doc.DocumentNode.SelectSingleNode("//div[@id='myTrips']"); 
var myTripsNode = HtmlNode.CreateNode(myTripsDiv.InnerHtml); 
var liOfTravels = myTripsNode.SelectNodes("//li"); 
Các vấn đề liên quan