我使用HtmlAgilityPack来解析webbrowser控件的html文档。我能够找到我想要的HtmlNode,但在获得HtmlNode之后,我想在WebbrowserControl.Document中重新调用相应的HtmlElement。
实际上HtmlAgilityPack解析了实时文档的离线副本,而我想访问webbrowser控件的实时元素来访问一些渲染属性,如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
}
如果元素有一个特定的属性,它可能很容易,但我想要一个适用于任何元素的解决方案。
请帮帮我,我该怎么办呢。
HtmlAgilityPack.HtmlNode
的XPath
属性显示从根到节点的路径上的节点。例如\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]"
脚步:
HtmlNode
您发现将所有父节点收集到根目录。