Gettig Htmlelement basato su HtmlAgilityPack.HtmlNode

c# html html-agility-pack webbrowser-control

Domanda

Io uso HtmlAgilityPack per analizzare il documento html di un controllo webbrowser. Sono in grado di trovare il mio HtmlNode desiderato, ma dopo aver ottenuto il HtmlNode, voglio riaccordare il corrispondente HtmlElement nel WebbrowserControl.Document.

Infatti HtmlAgilityPack analizza una copia offline del documento live, mentre voglio accedere agli elementi live del controllo webbrowser per accedere ad alcuni attributi resi come currentStyle o runtimeStyle

HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(webBrowser1.Document.Body.InnerHtml);
var some_nodes = doc.DocumentNode.SelectNodes("//p"); 
// this selection could be more sophisticated 
// and the answer shouldn't relay on it.
foreach (HtmlNode node in some_nodes)
{
   HtmlElement live_element = CorrespondingElementFromWebBrowserControl(node);
   // CorrespondingElementFromWebBrowserControl is what I am searching for
}

Se l'elemento avesse un attributo specifico potrebbe essere facile ma voglio una soluzione che funzioni su qualsiasi elemento.

Per favore aiutami cosa posso fare al riguardo.

Risposta accettata

l'attributo XPath di HtmlAgilityPack.HtmlNode mostra i nodi sul percorso dalla radice al nodo. Ad esempio \div[1]\div[2]\table[0] . È possibile attraversare questo percorso nel documento live per trovare l'elemento live corrispondente. Tuttavia, questo percorso potrebbe non essere preciso poiché HtmlAgilityPack rimuove alcuni tag come <form> quindi prima di utilizzare questa soluzione aggiungere nuovamente i tag omessi

HtmlNode.ElementsFlags.Remove("form");

struct DocNode  
{
    public string Name;
    public int Pos;
}
///// structure to hold the name and position of each node in the path

Il seguente metodo trova l'elemento live secondo XPath

    static public HtmlElement GetLiveElement(HtmlNode node, HtmlDocument doc)
    {
        var pattern = @"/(.*?)\[(.*?)\]"; // like div[1]
        // Parse the XPath to extract the nodes on the path
        var matches = Regex.Matches(node.XPath, pattern); 
        List<DocNode> PathToNode = new List<DocNode>();
        foreach (Match m in matches) // Make a path of nodes
        {
            DocNode n = new DocNode();
            n.Name = n.Name = m.Groups[1].Value;
            n.Pos = Convert.ToInt32(m.Groups[2].Value)-1;
            PathToNode.Add(n); // add the node to path 
        }

        HtmlElement elem = null; //Traverse to the element using the path
        if (PathToNode.Count > 0)
        {
            elem = doc.Body; //begin from the body
            foreach (DocNode n in PathToNode)
            {
                //Find the corresponding child by its name and position
                elem = GetChild(elem, n);                    
            }
        }
        return elem;
    }

il codice per il metodo GetChild usato sopra

    public static HtmlElement GetChild(HtmlElement el, DocNode node)
    {
        // Find corresponding child of the elemnt 
        // based on the name and position of the node
        int childPos = 0;
        foreach (HtmlElement child in el.Children)
        {
            if (child.TagName.Equals(node.Name, 
               StringComparison.OrdinalIgnoreCase))
            {
                if (childPos == node.Pos)
                {
                    return child;
                }
                childPos++;
            }                
        }
        return null;
    }

Risposta popolare

HtmlAgilityPack non è in grado di fornire direttamente l'accesso ai nodi direttamente in HTML. Dal momento che hai detto che non c'è uno stile / classe / ID distinto sull'elemento devi attraversare manualmente i nodi e trovare le corrispondenze.

Supponendo che HTML sia ragionevolmente valido (quindi sia il browser che HtmlAgilityPack eseguono la normalizzazione in modo simile) è possibile percorrere coppie di elementi a partire dalla radice di entrambi gli alberi e selezionando lo stesso nodo figlio.

Fondamentalmente puoi creare XPath "basato sulla posizione" sul nodo in un albero e selezionarlo in un altro albero. Xpath avrebbe un aspetto simile (a seconda che tu voglia prestare attenzione solo alle posizioni o alla posizione e al nome del nodo):

 "/*[1]/*[4]/*[2]/*[7]"
 "/body/div[2]/span[1]/p[3]"

passi:

  1. HtmlNode di HtmlNode hai trovato tutti i nodi principali fino alla radice.
  2. Ottenere la radice dell'elemento HTML nel browser
  3. per ogni livello di bambini trova la posizione del figlio corrispondente nella raccolta HtmlNodes nel passaggio 1 nel relativo genitore e trova HtmlElement live tra i figli del nodo attivo corrente.
  4. Passa al bambino appena trovato e torna indietro fino al nodo trovato che stai cercando.


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é