ottenere tutti i nodi e il suo contenuto usando htmldocument / HtmlAgilityPack

c# html html-agility-pack uwp

Domanda

Ho bisogno di ottenere tutti i nodi da un html, quindi da quei nodi ho bisogno di ottenere il testo e i sotto-nodi, e la stessa cosa, ma da quei sub-sub-nodi. Ad esempio, ho questo HTML:

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

Quindi ho bisogno di un modo per ottenere il nodo p , quindi il testo non formattato (questo), il solo testo in grassetto ( è a ), il collegamento in grassetto ( Link ) e il resto formattato e non formattato.

So che con htmldocument posso selezionare tutti i nodi e sub-nodi, ma, come posso ottenere il testo prima del sub-nodo, quindi il sub-nodo e il suo testo / sotto-nodi in modo da poter rendere la versione renderizzata del codice html ("Questo è un collegamento con grassetto ")?

Si prega di notare che l'esempio sopra è semplice. L'HTML avrebbe cose più complesse come lista, frame, elenco numerato, testo in formato triplo, ecc. Si noti inoltre che la cosa renderizzata non è un problema. L'ho già fatto, ma in un altro modo. Quello di cui ho bisogno è la parte per ottenere solo i nodi e il suo contenuto. Inoltre, non posso ignorare alcun nodo, quindi non posso filtrare nulla. E il nodo principale potrebbe iniziare come p, div, frame, ul, ecc.

Risposta accettata

Dopo aver esaminato l'htmldoc e le sue proprietà, e grazie all'osservazione di @HungCao, ho ottenuto un modo semplice e funzionante per interpretare un codice HTML.

Il mio codice è un po 'più complesso da aggiungere come esempio, quindi posterò una versione lite di esso.

Prima di tutto, deve essere caricato htmlDoc. Potrebbe essere su qualsiasi funzione:

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

Quindi dobbiamo interpretare ogni nodo "principale" (p in questo caso) e, in base al suo tipo, dobbiamo caricare una 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);
    }
}

Si noti che esiste una proprietà denominata "NodeType", ma non restituirà il tipo corretto. Quindi, usa la proprietà "Nome" (nota anche che la proprietà Name in htmlNode non è la stessa dell'attributo Name in HTML).

Infine, abbiamo la funzione InterNode che aggiungerà inline al Paragrafo (rif) riferito

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: so che ho detto che la mia app ha bisogno di renderizzare l'HTML in un altro modo che fa una webview, e so che questo codice di esempio genera la stessa cosa di una Webview, ma, come ho detto prima, questa è solo una lite versione del mio codice finale. In effetti, il mio codice originale / completo funziona come ho bisogno e questa è solo la base.



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché