基於HtmlAgilityPack.HtmlNode的Gettig Htmlelement

c# html html-agility-pack webbrowser-control

我使用HtmlAgilityPack來解析webbrowser控件的html文檔。我能夠找到我想要的HtmlNode,但在獲得HtmlNode之後,我想在WebbrowserControl.Document中重新調用相應的HtmlElement。

實際上HtmlAgilityPack解析了實時文檔的離線副本,而我想訪問webbrowser控件的實時元素來訪問一些渲染屬性,如currentStyleruntimeStyle

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
}

如果元素有一個特定的屬性,它可能很容易,但我想要一個適用於任何元素的解決方案。

請幫幫我,我該怎麼辦呢。

一般承認的答案

HtmlAgilityPack.HtmlNodeXPath屬性顯示從根到節點的路徑上的節點。例如\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查找live元素

    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. 對於每個級別的子級,在其父級的步驟1中找到HtmlNodes集合上相應子級的位置,然後在當前活動節點的子級中查找實時HtmlElement。
  4. 移動到新發現的孩子,然後回到3,直到找到您正在尋找的節點。


Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow