Gettig Htmlelement на основе HtmlAgilityPack.HtmlNode

c# html html-agility-pack webbrowser-control

Вопрос

Я использую HtmlAgilityPack для анализа html-документа элемента управления веб-браузером. Я могу найти желаемый HtmlNode, но после получения HtmlNode я хочу перенастроить соответствующий элемент HTML в WebbrowserControl.Document.

Фактически, HtmlAgilityPack анализирует автономную копию документа в реальном времени, в то время как я хочу получить доступ к живым элементам элемента управления веб-браузера для доступа к некоторым визуализированным атрибутам, таким как currentStyle или 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
}

Если элемент имеет определенный атрибут, это может быть легко, но я хочу, чтобы решение работало над любым элементом.

Пожалуйста, помогите мне, что я могу с этим поделать.

Принятый ответ

атрибут XPath HtmlAgilityPack.HtmlNode показывает узлы на пути от корня к узлу. Например, \div[1]\div[2]\table[0] . Вы можете пройти этот путь в реальном документе, чтобы найти соответствующий живой элемент. Однако этот путь может быть неточным, поскольку HtmlAgilityPack удаляет некоторые теги, такие как <form> затем перед использованием этого решения добавьте пропущенные теги обратно, используя

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

Следующий метод находит живой элемент в соответствии с 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;
    }

приведенный выше код для метода GetChild

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

Популярные ответы

HtmlAgilityPack определенно не может обеспечить доступ к узлам в прямом HTML напрямую. Поскольку вы сказали, что на элементе нет определенного стиля / класса / id, вам нужно вручную пройти через узлы и найти совпадения.

Предполагая, что HTML является достаточно обоснованным (поэтому оба браузера и HtmlAgilityPack выполняют нормализацию аналогично), вы можете перемещать пары элементов, начиная с корня обоих деревьев и выбрав один и тот же дочерний узел.

В принципе, вы можете построить «основанный на позиции» XPath для узла в одном дереве и выбрать его в другом дереве. Xpath будет выглядеть примерно так (в зависимости от того, вы хотите обратить внимание только на позиции или позицию и имя узла):

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

шаги:

  1. При использовании HtmlNode вы нашли сбор всех родительских узлов до корня.
  2. Получить корень элемента HTML в браузере
  3. для каждого уровня детей нахождение позиции соответствующего ребенка в коллекции HtmlNodes на шаге 1 в его родительском элементе, а также поиск живого HtmlElement среди детей текущего живого узла.
  4. Перейдите к вновь найденному ребенку и вернитесь до 3 до найденного узла, который вы ищете.


Related

Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему