2015-10-19 77 views
1

我正在使用HTML Agility Pack來定義返回網頁上鍊接的函數。問題是它返回包括mailto在內的所有鏈接。問題返回<a>不包含mailto鏈接的鏈接

在程序的後面,當處理鏈接時,mailto鏈接斷開。我試圖消除

我的函數定義爲它們在_links

的功能輸出列表包括:

var linkNodes = _htmlDocument.Value.DocumentNode.SelectNodes("//a"); 
if (linkNodes == null) 
    return Enumerable.Empty<Link>(); 

var links = new List<Link>(); 
foreach (var linkNode in linkNodes) 
{ 
    var href = linkNode.GetAttributeValue("href", "#"); 
    if (!Uri.IsWellFormedUriString(href, UriKind.RelativeOrAbsolute)) 
     continue; 

    var url = href.ToAbsoluteUri(Url); 
    var follow = linkNode.GetAttributeValue("rel", "follow"); 

    links.Add(new Link(Url, url, linkNode.InnerText, follow)); 
} 

_links = links; 

我的LINQ,幾乎工作(在擺脫郵寄地址的工作,但返回的字符串代替搭配使用的戰鬥機的節點):

var linkNodes = _htmlDocument.Value.DocumentNode.SelectNodes("//a[@href]") 
         .Select(a => a.Attributes["href"].Value) 
         .Where(href => !href.StartsWith("mailto:")) // skip emails, find only url links 
         .ToList(); 
+1

嘗試將您的linq改爲'htmlDocument.Value.DocumentNode.SelectNodes(「// a [@href]」)。其中(a =>!a.Attributes [「href」]。Value.StartsWith(「mailto: 「))。ToList();' –

+0

在其中一個迭代中出現錯誤:{」值不能爲空。\ r \ nParameter name:source「} – kacalapy

+1

嘗試使用空條件運算符(如果有c#6)。 'htmlDocument.Value.DocumentNode.SelectNodes(「// a [@href]」)。其中(a =>!a.Attributes [「href」]。Value?.StartsWith(「mailto:」)?? false)。 ToList();' –

回答

2

關於選擇和地點:

Accordi ng到MSDN

Linq Select將根據該集合的項目將您的集合轉換爲新的表單。這是一個簡單的例子。

IEnumerable<int> collectionOfInt = Enumerable.Range(0, 10); 
IEnumerable<string> collectionOfString = collectionOfInt.Select(i => i.ToString()); 
IEnumerable<int> lengthOfStrings = collectionOfString.Select(str => str.Length); 

首先你的int從0集合到9正如你可以看到選擇"0","1",...,"9"返回字符串的一個新的集合,但基於對collectionOfInt項目,你必須字符串。請注意,Select的執行被延遲,因此必須使用ToList來實際執行該查詢。

collectionOfString上執行Select時也是這樣。正如你可以看到你放棄實際的字符串,你會得到這些字符串的長度(1,1,...,1)。現在

您的LINQ

var linkNodes = _htmlDocument.Value.DocumentNode.SelectNodes("//a[@href]") 
        .Select(a => a.Attributes["href"].Value) 
        .Where(href => !href.StartsWith("mailto:")) 
        .ToList(); 

同樣的事情發生在這裏。你有一組節點,但Select(a => a.Attributes["href"].Value)會實際上將你的節點變成字符串的集合,並且你將失去實際的節點。

.Select(a => a.Attributes["href"].Value) // Changes main collection into values 
.Where(href => !href.StartsWith("mailto:")) // searches on values not main collection thus returns values again. 

所以你必須把它全部放在Where部分。因爲Where不會更改集合類型。當元素上的條件爲真時,它只會從集合中選擇元素。

根據我的解釋,href以前的查詢是a.Attributes["href"].Value。因此,爲了不松原始元素只是包裝a.Attributes["href"].Valuehref所以,你將有

.Where(node => !node.Attributes["href"].Value.StartsWith("mailto:")) // searches on nodes collection thus returns nodes 

關於空例外部分:

Where Linq查詢將不會是空的物品進行搜索。所以只要前面查詢中的hrefa.Attributes["href"].Value爲空,它就會跳過該項而不選擇它。

在您嵌入Select轉換爲Where現在,其中只有node的可空性檢查不執行功能!node.Attributes["href"].Value.StartsWith("mailto:")

基本上因爲Value有空的可能性,你會在StartsWith("mailto:")上得到例外,它不能處理null。

在C#6中,您可以通過混合null conditionalNull-coalescing運算符來修復此問題。

htmlDocument.Value.DocumentNode.SelectNodes("//a[@href]") 
    .Where(node => !node.Attributes["href"].Value?.StartsWith("mailto:") ?? false).ToList(); 

如果Value?.值爲null,它不會繼續執行StartsWith("mailto:"),而是空直接返回。

因爲返回類型?.nullable bool,所以當運算符的左側是空時,?? false將返回false。