问题返回 <a> link 不包括 mailto links
Issue returning <a> link excluding mailto links
我正在使用 HTML Agility Pack 来定义 returns 网页链接的功能。问题是它 returns 所有链接包括 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 几乎可以工作(在摆脱 mailto 方面工作,但返回的是字符串而不是与所用战士匹配的节点):
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();
关于 Select 和地点:
根据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);
首先,您有一个从 0 到 9 的 int
集合。如您所见,Select return 是一个新的字符串集合,但基于 collectionOfInt
的项目所以你有来自 "0","1",...,"9"
的字符串。请注意,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"].Value
包裹在 href
内,这样您将拥有
.Where(node => !node.Attributes["href"].Value.StartsWith("mailto:")) // searches on nodes collection thus returns nodes
关于Null异常部分:
Where
Linq 查询不会搜索空项。因此,只要先前查询中的 href
或 a.Attributes["href"].Value
为空,它就会跳过该项目而不选择它。
将 Select
内联到 Where
后,现在只检查 node
的可空性而不检查函数 !node.Attributes["href"].Value.StartsWith("mailto:")
.
的执行
基本上是因为 Value
有可能为 null,你会在 StartsWith("mailto:")
上遇到无法处理 null 的异常。
在 C#6 中,您可以通过混合 null conditional
and Null-coalescing
运算符来解决此问题。
htmlDocument.Value.DocumentNode.SelectNodes("//a[@href]")
.Where(node => !node.Attributes["href"].Value?.StartsWith("mailto:") ?? false).ToList();
如果Value?.
的值为null,则不会继续执行StartsWith("mailto:")
,而是直接returns null。
因为 ?.
的 return 类型是 nullable bool
那么 ?? false
将 return false 当运算符的左侧为空时。
我正在使用 HTML Agility Pack 来定义 returns 网页链接的功能。问题是它 returns 所有链接包括 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 几乎可以工作(在摆脱 mailto 方面工作,但返回的是字符串而不是与所用战士匹配的节点):
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();
关于 Select 和地点:
根据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);
首先,您有一个从 0 到 9 的 int
集合。如您所见,Select return 是一个新的字符串集合,但基于 collectionOfInt
的项目所以你有来自 "0","1",...,"9"
的字符串。请注意,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"].Value
包裹在 href
内,这样您将拥有
.Where(node => !node.Attributes["href"].Value.StartsWith("mailto:")) // searches on nodes collection thus returns nodes
关于Null异常部分:
Where
Linq 查询不会搜索空项。因此,只要先前查询中的 href
或 a.Attributes["href"].Value
为空,它就会跳过该项目而不选择它。
将 Select
内联到 Where
后,现在只检查 node
的可空性而不检查函数 !node.Attributes["href"].Value.StartsWith("mailto:")
.
基本上是因为 Value
有可能为 null,你会在 StartsWith("mailto:")
上遇到无法处理 null 的异常。
在 C#6 中,您可以通过混合 null conditional
and Null-coalescing
运算符来解决此问题。
htmlDocument.Value.DocumentNode.SelectNodes("//a[@href]")
.Where(node => !node.Attributes["href"].Value?.StartsWith("mailto:") ?? false).ToList();
如果Value?.
的值为null,则不会继续执行StartsWith("mailto:")
,而是直接returns null。
因为 ?.
的 return 类型是 nullable bool
那么 ?? false
将 return false 当运算符的左侧为空时。