Gettig Htmlelement basado en HtmlAgilityPack.HtmlNode

c# html html-agility-pack webbrowser-control

Pregunta

Utilizo HtmlAgilityPack para analizar el documento html de un control de navegador web. Puedo encontrar el HtmlNode deseado, pero después de obtener el HtmlNode, deseo volver a ejecutar el elemento HtmlElement correspondiente en el WebbrowserControl.Document.

De hecho, HtmlAgilityPack analiza una copia fuera de línea del documento en vivo, mientras que yo quiero acceder a los elementos en vivo del control del currentStyle runtimeStyle para acceder a algunos atributos renderizados como 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
}

Si el elemento tuviera un atributo específico, podría ser fácil, pero quiero una solución que funcione con cualquier elemento.

Por favor, ayúdame, ¿qué puedo hacer al respecto?

Respuesta aceptada

El atributo XPath del HtmlAgilityPack.HtmlNode muestra los nodos en la ruta desde la raíz hasta el nodo. Por ejemplo, \div[1]\div[2]\table[0] . Puede recorrer esta ruta en el documento en vivo para encontrar el elemento en vivo correspondiente. Sin embargo, esta ruta puede no ser precisa, ya que HtmlAgilityPack elimina algunas etiquetas como <form> luego, antes de usar esta solución, agregue las etiquetas omitidas nuevamente usando

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

El siguiente método encuentra el elemento vivo de acuerdo con la 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;
    }

el código para el método GetChild utilizado anteriormente

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

Respuesta popular

HtmlAgilityPack definitivamente no puede proporcionar acceso a nodos en HTML directo directamente. Como dijo que no hay un estilo / clase / id distinto en el elemento, tiene que recorrer los nodos manualmente y encontrar coincidencias.

Suponiendo que HTML es razonablemente válido (de modo que tanto el navegador como HtmlAgilityPack realizan la normalización de manera similar) puede caminar pares de elementos comenzando desde la raíz de ambos árboles y seleccionando el mismo nodo secundario.

Básicamente, puede crear XPath "basado en posición" para nodos en un árbol y seleccionarlo en otro árbol. Xpath se vería como (dependiendo de si quieres prestar atención a solo las posiciones o la posición y el nombre del nodo):

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

Pasos:

  1. Al usar HtmlNode , has encontrado recopilar todos los nodos principales hasta la raíz.
  2. Obtener la raíz del elemento de HTML en el navegador
  3. para cada nivel de niños, encuentre la posición del hijo correspondiente en la colección HtmlNodes en el paso 1 en su elemento primario y encuentre el elemento HtmlElement en vivo entre los niños del nodo Live actual.
  4. Mueva al niño recién encontrado y regrese a 3 hasta el nodo encontrado que está buscando.


Related

Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow