2012-01-20 89 views
5

Đây là mẫu HTML Tôi đang cố gắng phân tích cú pháp với Gói nhanh nhạy Html trong ASP.Net (C#).Phân tích cú pháp dl với HtmlAgilityPack

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

Các giá trị tôi muốn là:

  • Các siêu liên kết -> 1.html
  • Các Anchor Text -> 1
  • Nội Tiêu od dd -> Đầu tiên nhập

(Tôi đã lấy ví dụ về mục nhập đầu tiên tại đây nhưng tôi muốn các giá trị cho các thành phần này cho tất cả các mục nhập trong danh sách)

Đây là mã Tôi hiện đang sử dụng,

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

Vấn đề là tôi có được các giá trị cho các liên kết và các văn bản neo một cách chính xác nhưng đối với các văn bản bên trong của nó chỉ mất giá trị của các mục nhập đầu tiên và điền vào cùng một giá trị cho tất cả các mục nhập khác cho tổng số lần phần tử xảy ra và sau đó nó bắt đầu lại với phần tử thứ hai. Tôi không có thể rõ ràng trong lời giải thích của tôi vì vậy đây là một đầu ra mẫu Tôi nhận với mã này:

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 

Trong khi tôi đang cố gắng để có được

First Entry  1.html  1 
Second Entry  2.html  2 
Third Entry  3.html  3 

Tôi khá mới để HAP và có rất ít hiểu biết về xpath, vì vậy tôi chắc chắn rằng tôi đang làm điều gì đó sai ở đây, nhưng tôi không thể làm cho nó hoạt động ngay cả sau khi chi tiêu giờ trên đó. Bất kì sự trợ giúp nào đều được đánh giá cao.

Trả lời

4

Giải pháp 1

tôi đã xác định một chức năng mà đưa ra một nút dt sẽ trả lại dd nút tiếp theo sau nó:

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

và bây giờ mã LINQ có thể được chuyển thành:

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

Giải pháp 2

Nếu không có chức năng bổ sung:

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

Cảm ơn rất nhiều, hoạt động. Tuy nhiên tôi không hiểu chính xác những gì đang xảy ra ở đây. Nó có thể được thực hiện mà không có một chức năng, sử dụng một số loại xpath/regex? Giải pháp này là hoàn toàn tốt cho tôi, tôi chỉ tò mò làm thế nào nó hoạt động. Sẽ rất tuyệt nếu bạn có thể đưa ra một lời giải thích ngắn gọn, cảm ơn. – redGREENblue

+1

Vấn đề là chúng ta cần một cái gì đó như "đưa thẻ' dt' này, hãy cho tôi thẻ 'dd' xuất hiện ngay sau nó". Tôi đã cố gắng để làm cho nó đơn giản hơn, bằng cách chọn ddElement như là dtElement.NextSibling, nhưng HtmlAgilityPack xem xét nút tiếp theo là khoảng trống giữa các thẻ '

' và '
'. Điều này dẫn tôi đến giải pháp hơi xấu xí mà bạn thấy ở trên. – GolfWolf

+1

Tôi chỉ tìm ra một giải pháp có thể khác không liên quan đến việc khai báo hàm - vui lòng xem câu trả lời được cập nhật. – GolfWolf

2

Chỉ cần một ví dụ về cách bạn có thể phân tích cú pháp một số phần tử bằng cách sử dụng 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; 
} 
Các vấn đề liên quan