【问题标题】:node.Descendants(0) seems to return all child nodes instead of first levelnode.Descendants(0) 似乎返回所有子节点而不是第一级
【发布时间】:2018-12-13 07:50:11
【问题描述】:

我正在使用 HtmlAgilityPack 一次遍历一个级别的文档树。但是,似乎调用node.Descendants(0) 会返回整个节点树。

注意:我尝试粘贴逐字 HTML 字符串,但 SE 解析器不喜欢它,所以我将其添加为 sn-p。

<html>
    <head>
    <meta name="generator"
    content="HTML Tidy for HTML5 (experimental) for Windows https://github.com/w3c/tidy-html5/tree/c63cc39" />
    <title></title>
    </head>
    <body>
    <p id="p1" class="newline">
        <span id="span1" class="bold">
        <span id="span2" class="literal">BOLD TEXT</span>
        </span>
    </p>
    </body>
</html>
var doc = new HtmlAgilityPack.HtmlDocument();

doc.LoadHtml(html);

var lines = doc.DocumentNode.Descendants().Where(x => x.HasClass("newline")).ToArray();

Console.WriteLine(string.Join("\r\n", lines[0].Descendants(0)
    .Select(x => $"{x.Name} {x.Id} {(x as HtmlTextNode)?.Text}")));

以上代码的作用是获取第一个p 标签的后代。如果我将01 作为参数传递,它将返回整个节点树并在下面输出。问题是包含BOLD TEXT 的文本节点嵌套在p 标签下方3 层。使用上面的代码,我只希望它返回一个文本节点span1,然后返回另一个文本节点。

我在拨打.Descendants 时做错了什么?

#text

span span1
#text

span span2
#text  BOLD TEXT
#text

#text

编辑:一个临时的解决方法是确保您只获得父节点等于当前节点的后代。不过,仍在寻找更实用的解决方案。

Console.WriteLine(string.Join("\r\n", lines[0].Descendants(0)
    .Where(x => x.ParentNode == lines[0])
    .Select(x => $"{x.Name} {x.Id} {(x as HtmlTextNode)?.Text}")));

【问题讨论】:

    标签: .net html-agility-pack


    【解决方案1】:

    我遇到了同样的问题,开始搜索并找到了您的问题 :)。然后我decided to ask developers directly。这是答案的简短版本:

    根据代码,它的行为方式不同:

    /// <summary>
    /// Gets all Descendant nodes in enumerated list
    /// </summary>
    /// <returns></returns>
    public IEnumerable<HtmlNode> Descendants(int level)
    {
        if (level > HtmlDocument.MaxDepthLevel)
        {
            throw new ArgumentException(HtmlNode.DepthLevelExceptionMessage);
        }
    
        foreach (HtmlNode node in ChildNodes)
        {
            yield return node;
    
            foreach (HtmlNode descendant in node.Descendants(level + 1))
            {
                yield return descendant;
            }
        }
    }
    

    它通过将级别增加一来获取所有后代并获取子代,直到不再有后代或达到最大级别(int.MaxValue)。 但是,我同意你的观点,它可能应该返回后代,直到达到指定的级别。 不幸的是,为了向后兼容,我们可能不会对这种方法做任何事情,以免影响当前的应用程序。

    但是,在您的情况下,可以使用 ChildNodes 代替 Descendants(0)。代码如下所示:

        Console.WriteLine(string.Join("\r\n", lines[0].ChildNodes
                                .Select(x => $"{x.Name} {x.Id} {(x as HtmlTextNode)?.Text}")));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-20
      • 1970-01-01
      • 2016-03-26
      • 1970-01-01
      • 2023-01-12
      • 1970-01-01
      • 2019-03-04
      相关资源
      最近更新 更多