node.Descendants (0) semble renvoyer tous les nœuds enfants au lieu du premier niveau

.net html-agility-pack

Question

J'utilise HtmlAgilityPack pour parcourir une arborescence de documents, un niveau à la fois. Cependant, il semble que l'appel de node.Descendants(0) renvoie la totalité de l'arborescence de nœuds.

Remarque: j'ai essayé de coller dans ma chaîne HTML verbatim, mais l'analyseur syntaxique SE ne l'aimant pas, je l'ai donc ajouté sous forme d'extrait.

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

Le code ci-dessus récupère les descendants de la première balise p . Si je passe 0 ou 1 en argument, il renvoie l’arbre de nœud entier et les résultats ci-dessous. Le fait est que le nœud de texte contenant BOLD TEXT est imbriqué à 3 niveaux de la balise p . Avec le code ci-dessus, je m'attendrais seulement à ce qu'il renvoie un nœud de texte, span1 , puis un autre nœud de texte.

Qu'est-ce que je fais de mal dans mon appel à .Descendants ?

#text

span span1
#text

span span2
#text  BOLD TEXT
#text

#text

Edit: une solution temporaire consiste à s'assurer que vous n'obtenez que des descendants où le parent est égal au nœud actuel. Toujours à la recherche d'une solution plus pratique, cependant.

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

Réponse populaire

J'ai eu le même problème, j'ai commencé à googler et j'ai trouvé votre question :). Et puis j'ai décidé de demander directement aux développeurs . Et voici une version courte de la réponse:

Selon le code, il se comporte différemment:

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

Il prend tous les descendants et prend les enfants en incrémentant le niveau de un jusqu'à ce que plus aucun descendant ou le niveau maximum ne soit atteint (int.MaxValue). Cependant, je suis d'accord avec vous, il devrait probablement renvoyer un descendant jusqu'à ce que le niveau spécifié soit atteint. Malheureusement, pour des raisons de compatibilité ascendante, nous ne ferons probablement rien sur cette méthode pour ne pas affecter les applications actuelles.

Cependant, dans votre cas, les ChildNodes peuvent être utilisés à la place de Descendants(0) . Le code ressemblera à ceci:

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


Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi