在 xpath 中使用“.//”

Use of ".//" in xpath

SO 上有很多关于 Xpath 不能与 HtmlAgilityPack 一起工作的问题。我读了六本,但没有找到解决我的问题的方法。

我想 select 任何级别的 "form" 元素内的所有 "input" 元素。

我希望它能工作:

var all = html.DocumentNode.SelectNodes("//form//input");

它没有 - 没有返回任何元素。这也不起作用(在此测试用例中假设有一个表单元素,以缩小问题范围):

var node = html.DocumentNode.SelectSingleNode("//form");
var nodes = node.SelectNodes(".//input");

现在,以上所有内容自然适用于 xml:

XmlDocument d = new XmlDocument();
d.LoadXml("<html><body><form><div><input></input></div></form></body></html>");
var xmlNode = d.SelectSingleNode("//form");
var xmlNodes = xmlNode.SelectNodes(".//input");
Console.WriteLine($"Two step xml: {xmlNodes?.Count}");
var xmlAll = d.SelectNodes("//form//input");
Console.WriteLine($"One step xml: {xmlAll?.Count}");

如预期的那样,上面的两种情况都显示计数为 1。

现在是 HtmlAgilityPack 的示例,它不起作用:

string test = @"<!DOCTYPE html>
<html lang=""en"" xmlns=""http://www.w3.org/1999/xhtml"">
<head id=""Head1"">    
  <body>
    <form method=""post"" action=""/SignIn"" id=""mainform"">
      <div class=""aspNetHidden"">
        <input type=""hidden"" name=""hello"" id=""hello"" value="""" />
      </div>
    </form>
  </body>
</html>";


HtmlDocument html = new HtmlDocument();
html.LoadHtml(test);
var node = html.DocumentNode.SelectSingleNode("//form");
var nodes = node.SelectNodes(".//input");
Console.WriteLine($"Two steps html: {nodes?.Count}");
var all = html.DocumentNode.SelectNodes("//form//input");
Console.WriteLine($"One step html: {all?.Count}");

这里没有显示1,因为没有找到节点。

为什么?是否可以在不求助于 loops/code 的情况下修复 xpath 表达式?

我正在设计一个 class 需要接受单个 xpath 表达式(可能用于配置 and/or 数据存储)以了解它需要处理的节点子集。

所以你的代码没有问题。问题是 HTMLAgilityPack 本身。 基本上你需要添加这一行 HtmlNode.ElementsFlags.Remove("form");

根据花岗岩龙评论:

There are indeed a lot of questions regarding HtmlAgilityPack and xpath, mostly because its xpath implementation is incorrect and not up with generic xpath specifications.