【问题标题】:Xpath expression to LINQ expressionXpath 表达式到 LINQ 表达式
【发布时间】:2013-10-29 23:34:16
【问题描述】:

我已将此 XPath 表达式重写为 linq,但有问题(未找到元素异常)。 我的 HTML:

string xml = @"
<root>
   <div id=""main"">
      <div class=""content"">
         <ul>
            something
         </ul>
      </div>
      <div class=""content"">
         <ul>
            something
         </ul>
      </div>
      <div class=""content"">
         <ul>
            <li>
               <div>My text</div>
            </li>
         </ul>
      </div>
   </div>
</root>
";

Xpath:

//div[@id="main"]//div[@class="content"]/ul/li/div

LINQ:

string Content =
            doc.DocumentNode.Descendants("div").First(x => x.GetAttributeValue("id", null) == "main")
                .Descendants("div").First(x => x.GetAttributeValue("class", null) == "content")
                .Descendants("ul").First()
                .Descendants("li").First()
                .Descendants("div").First().InnerText

背景:我必须使用 LINQ,因为我使用的是 Portable 库。

我已经用稍微不同的表达方式解决了我的问题:

string Content =
            doc.DocumentNode.Descendants("div").First(x => x.GetAttributeValue("id", null) == "main")
                .Descendants("div").Where(x => x.GetAttributeValue("class", null) == "content").ElementAt(2)
                .Descendants("ul").First()
                .Descendants("li").First()
                .Descendants("div").First().InnerText;

它可以工作,但它与 Xpath 不同。

所以我问你:是否存在 LINQ 表达式,它在没有指定确切位置的情况下找到带有 InnerText 的节点(如 Xpath)?

【问题讨论】:

  • 当你尝试你写的东西时会发生什么?
  • //div.. 查找所有具有属性 id = main 的 div;不仅是第一个...
  • 是原来的 //div[@id="main"]//div[@class="content"] 或 //div[@id="main"]/div[@class="内容"] ?
  • 这是原创的 //div[@id="main"]//div[@class="content"]/ul/li/div
  • 你不想要后代,你想要元素 - 后代找到所有匹配的孩子(包括孙子、曾孙、失散多年的继孙、那一晚的孩子等)。你只想要直接的孩子,所以使用元素...

标签: c# linq xpath html-agility-pack


【解决方案1】:

此代码将检索目标 div 的 InnerText:

var doc = new HtmlDocument();

string xml = @"<root>
                  <div id=""main"">
                    <div class=""content"">
                        <ul>
                            <li>
                                <div>Test</div>
                            </li>
                        <ul>
                    </div>
                  </div>
                </root>";

var bytes = System.Text.Encoding.UTF8.GetBytes(xml);
var memStream = new MemoryStream(bytes);

doc.Load(memStream);

var innerText =
doc.DocumentNode.Descendants("div").Where(x => x.GetAttributeValue("id", null) == "main").First()
.Descendants("div").Where(x => x.GetAttributeValue("class", null) == "content").First()
.Elements("ul").First()
.Elements("li").First()
.Elements("div").First().InnerText;

运行时“innerText”等于“Test”(即 div 的 innerText)

【讨论】:

  • 这个表达式仍然没有返回任何元素。
  • 在我做过的测试中确实如此,我会更新我的答案。
  • 您给我的解决方案实际上与我的问题相同。元素或后代 - 在这种情况下是相同的。您也可以将 where() 替换为 first()。
【解决方案2】:

我认为这就是您想要的...您期望文档中的第一个匹配项,而不是所有匹配项,对吗?

string Content =
    doc.DocumentNode.Descendants("div").Where(x => x.GetAttributeValue("id", null) == "main")
        .Descendants("div").Where(x => x.GetAttributeValue("class", null) == "content")
        .Elements("ul")
        .Elements("li")
        .Elements("div").First().Value;

一般...

XPath '//' -> 转换为 LINQ .Descendants

XPath '/' -> 转换为 LINQ .Elements

【讨论】:

  • 无法调试> Elements("something").Elements("something2")
猜你喜欢
  • 2013-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多