返回<a>链接排除邮件链接的问题



我正在使用HTML敏捷包来定义一个返回网页链接的函数。问题是它返回包括 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();

关于选择和位置:

根据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 返回一个新的字符串集合,但基于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不会改变集合类型。仅当该元素的条件为 true 时,它才会从集合中选择元素。

根据我的解释,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

关于空异常部分:

Where Linq 查询不会搜索空项。 因此,只要上一个查询中的hrefa.Attributes["href"].Value为 null,它就会跳过该项而不选择它。

在你内联Select到现在Where,只检查node的可空性,而不执行函数!node.Attributes["href"].Value.StartsWith("mailto:")

基本上是因为Value有可能出现 null,所以您将在无法处理 null 的StartsWith("mailto:")上获得异常。

在 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:"),而是直接返回 null。

因为?.的返回类型是nullable bool所以当运算符的左侧为 null 时?? false将返回 false。

最新更新