node.Descendants (0) parece devolver todos los nodos secundarios en lugar del primer nivel

.net html-agility-pack

Pregunta

Estoy usando HtmlAgilityPack para atravesar un árbol de documentos de un nivel a la vez. Sin embargo, parece que llamar a node.Descendants(0) devuelve el árbol de nodos completo.

Nota: Intenté pegar en mi cadena HTML literal, pero al analizador SE no le gustó, así que lo agregué como un fragmento.

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

Lo que hace el código anterior es obtener los primeros descendientes de la etiqueta p . Si paso 0 o 1 como argumento, devuelve el árbol de nodos completo y las salidas a continuación. La cosa es que el nodo de texto que contiene BOLD TEXT está anidado 3 niveles por debajo de la etiqueta p Con el código anterior, solo esperaría que devolviera un nodo de texto, span1 , y luego otro nodo de texto.

¿Qué estoy haciendo mal en mi llamada a .Descendants ?

#text

span span1
#text

span span2
#text  BOLD TEXT
#text

#text

Editar: una solución temporal es asegurarse de que solo obtenga descendientes donde el padre sea igual al nodo actual. Sin embargo, sigue buscando una solución más práctica.

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

Respuesta popular

Tengo el mismo problema, comencé a buscar en Google y encontré tu pregunta :). Y luego decidí preguntarle directamente a los desarrolladores . Y aquí hay una versión corta de la respuesta:

Según el código se comporta de forma diferente:

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

Toma todos los descendientes y los hijos incrementando el nivel en uno hasta que no se alcanza más descendiente o se alcanza el nivel máximo (int.MaxValue). Sin embargo, estoy de acuerdo con usted, probablemente debería devolver descendiente hasta que se alcance el nivel especificado. Desafortunadamente, para la compatibilidad con versiones anteriores, es probable que no hagamos nada con este método para no afectar las aplicaciones actuales.

Sin embargo, en su caso, se pueden usar ChildNodes lugar de Descendants(0) . El código se verá como:

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



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué