obtenga todos los nodos y su contenido utilizando htmldocument / HtmlAgilityPack

c# html html-agility-pack uwp

Pregunta

Necesito obtener todos los nodos de un html, luego de esos nodos necesito obtener el texto y los subnodos, y lo mismo, pero de esos subnodos secundarios. Por ejemplo, tengo este HTML:

<p>This <b>is a <a href="">Link</a></b> with <b>bold</b></p>

Así que necesito una forma de obtener el nodo p , luego el texto sin formato (este), el único texto en negrita ( es a ), el enlace en negrita ( Enlace ) y el resto con formato y no con formato de texto.

Sé que con el htmldocument puedo seleccionar todos los nodos y subnodos, pero, ¿cómo puedo obtener el texto antes del subnodo, luego el subnodo y su texto / subnodos para que pueda hacer la versión renderizada? de la html ("Este es un enlace con negrita ")?

Tenga en cuenta que el ejemplo anterior es simple. El HTML tendría cosas más complejas como listas, marcos, listas numeradas, texto con triple formato, etc. También tenga en cuenta que lo renderizado no es un problema. Ya lo he hecho pero de otra manera. Lo que necesito es la parte para obtener los nodos y su contenido solamente. Además, no puedo ignorar ningún nodo, así que no puedo filtrar por nada. Y el nodo principal podría comenzar como p, div, frame, ul, etc.

Respuesta aceptada

Después de buscar en htmldoc y sus propiedades, y gracias a la observación de @HungCao, obtuve una manera simple de interpretar un código HTML.

Mi código es un poco más complejo para agregarlo como ejemplo, así que publicaré una versión liviana de él.

En primer lugar, el htmlDoc tiene que ser cargado. Podría estar en cualquier función:

HtmlDocument htmlDoc = new HtmlDocument();
string html = @"<p>This <b>is a <a href="""">Link</a></b> with <b>bold</b></p>";
htmlDoc.LoadHtml(html);

Luego necesitamos interpretar cada nodo "principal" (p en este caso) y, dependiendo de su tipo, necesitamos cargar un LoopFunction (InterNode)

HtmlNodeCollection nodes = htmlDoc.DocumentNode.ChildNodes;

foreach (HtmlNode node in nodes)
{
    if(node.Name.ToLower() == "p") //Low the typeName just in case
    {
        Paragraph newPPara = new Paragraph();
        foreach(HtmlNode childNode in node.ChildNodes)
        {
            InterNode(childNode, ref newPPara);
        }
        richTextBlock.Blocks.Add(newPPara);
    }
}

Tenga en cuenta que hay una propiedad llamada "NodeType", pero no devolverá el tipo correcto. Entonces, en lugar de eso, use la propiedad "Nombre" (también tenga en cuenta que la propiedad Nombre en htmlNode no es lo mismo que el atributo Nombre en HTML).

Finalmente, tenemos la función InterNode que agregará líneas en el párrafo (ref) referido

public bool InterNode(HtmlNode htmlNode, ref Paragraph originalPar)
{
    string htmlNodeName = htmlNode.Name.ToLower();

    List<string> nodeAttList = new List<string>();
    HtmlNode parentNode = htmlNode.ParentNode;
    while (parentNode != null) {
        nodeAttList.Add(parentNode.Name);
        parentNode = parentNode.ParentNode;
    } //we need to get it multiple types, because it could be b(old) and i(talic) at the same time.

    Inline newRun = new Run();
    foreach (string noteAttStr in nodeAttList) //with this we can set all the attributes to the inline
    {
        switch (noteAttStr)
        {
            case ("b"):
            case ("strong"):
                {
                    newRun.FontWeight = FontWeights.Bold;
                    break;
                }
            case ("i"):
            case ("em"):
                {
                    newRun.FontStyle = FontStyle.Italic;
                    break;
                }
        }
    }

    if(htmlNodeName == "#text") //the #text means that its a text node. Like <i><#text/></i>. Thanks @HungCao
    {
        ((Run)newRun).Text = htmlNode.InnerText;
    } else //if it is not a #text, don't load its innertext, as it's another node and it will always have a #text node as a child (if it has any text)
    {
        foreach (HtmlNode childNode in htmlNode.ChildNodes)
        {
            InterNode(childNode, ref originalPar);
        }
    }

    return true;
}

Nota: Sé que dije que mi aplicación necesita representar el HTML de otra manera que lo hace una vista web, y sé que este código de ejemplo genera lo mismo que una vista web, pero, como dije antes, esto es solo un poco Versión de mi código final. De hecho, mi código original / completo funciona como necesito y esto es solo la base.



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é