XPath/HtmlAgilityPack:如何查找具有属性 (href) 特定值的元素 (a) 并查找相邻的表列?

Posted

技术标签:

【中文标题】XPath/HtmlAgilityPack:如何查找具有属性 (href) 特定值的元素 (a) 并查找相邻的表列?【英文标题】:XPath/HtmlAgilityPack: How to find an element (a) with a specific value for an attribute (href) and find adjacent table columns? 【发布时间】:2011-11-09 20:25:10 【问题描述】:

我非常绝望,因为我不知道如何实现我在问题中所说的。我已经阅读了无数类似的例子,但没有找到一个在确切情况下有效的例子。所以,假设我有以下代码:

<table><tr>
<td><a href="url-a">text A</a></td><td><a>id A</a></td><td><a>img A</a></td>
<td><a href="url-b">text B</a></td><td><a>id B</a></td><td><a>img B</a></td>
<td><a href="url-c">text C</a></td><td><a>id C</a></td><td><a>img C</a></td>
</tr></table>

现在,我已经拥有的是 url-a 的一部分。我基本上想知道如何获得 id A 和 img A。我正在尝试使用 XPath “找到”这条线,但我无法找到使其工作的方法。此外,信息可能根本不存在。这是我最近的尝试(说真的,我已经修改了 3 个多小时,现在尝试了许多不同的方法):

if (htmlDoc.DocumentNode.SelectSingleNode(@"/a[contains(@href, 'part-url-a')]") != null)
    string ida = htmlDoc.DocumentNode.SelectSingleNode(@"/a[contains(@href, 'part-url-a')]/following-sibling::a").InnerText;

好吧,这显然是错误的,所以如果有人能在这里帮助我,我会非常高兴。另外,如果有人可以向我指出一些网站,该网站详细解释了 XPath 和符号/语法,并附有类似这样的示例,我将不胜感激。也欢迎书籍。

PS:我知道我完全可以在没有 XPath 的情况下使用 Regex 或仅使用 C# 中的简单 StreamReader 来实现我的目标,并检查每一行是否包含我需要的内容,但是 a) 它对我的需求来说太脆弱了,因为代码可能突然出现换行符和 b) 对于我在这个项目中所做的任何事情,我真的希望完全坚持使用 XPath。

提前感谢您的帮助!

【问题讨论】:

好问题,+1。有关选择所需文本节点的确切 XPath 表达式,请参阅我的答案。 【参考方案1】:

使用以下 XPath 表达式

   /*/tr/td[a[@href='url-a']]
                /following-sibling::td[1]
                     /a/text()

根据提供的(格式错误但已更正)的 XML 文档进行评估时

<table><tr>
<td><a href="url-a">text A</a></td><td><a>id A</a></td><td><a>img A</a></td>
<td><a href="url-b">text B</a></td><td><a>id B</a></td><td><a>img B</a></td>
<td><a href="url-c">text C</a></td><td><a>id C</a></td><td><a>img C</a></td>
</tr></table>

想要的文本节点被选中

id A

同样,这个 XPath 表达式

   /*/tr/td[a[@href='url-a']]
                /following-sibling::td[2]
                     /a/text()

当针对同一个 XML 文档(上图)进行评估时,选择另一个想要的文本节点

img A

基于 XSLT 的验证

当此转换应用于 XML 文档时(上):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:copy-of select=
   "/*/tr/td[a[@href='url-a']]
                /following-sibling::td[1]
                     /a/text()"/>

  <xsl:text>&#10;</xsl:text>
  <xsl:copy-of select=
   "/*/tr/td[a[@href='url-a']]
                /following-sibling::td[2]
                     /a/text()"/>
 </xsl:template>
</xsl:stylesheet>

产生了想要的结果

id A
img A

【讨论】:

我也会尝试您的解决方案并报告其效果。谢谢。 好的,我需要做一些调整(例如,因为我只有部分 url 而不是完整的匹配)但总而言之,它就像一个魅力!非常感谢。它不仅帮助我解决了这个问题,而且我终于明白了 XPath 语法在实践中的实际工作原理。我还会看看你的 XPath Visualizer,猜猜这正是我需要的 :-)【参考方案2】:

您有一个严重损坏的 HTML,带有不匹配的结束 td 标记。请修复它们。这只是一个丑陋的图片这个标记。

这就是说希望 Html Agility Pack 可以处理你扔给它的任何垃圾,所以这里是如何继续并解析你拥有的垃圾并在给定 href 的情况下找到 idimg 值:

class Program

    static void Main()
    
        var doc = new HtmlDocument();
        doc.Load("test.html");
        var anchor = doc.DocumentNode.SelectSingleNode("//a[contains(@href, 'url-a')]");
        if (anchor != null)
        
            var id = anchor.ParentNode.SelectSingleNode("following-sibling::td/a");
            if (id != null)
            
                Console.WriteLine(id.InnerHtml);
                var img = id.ParentNode.SelectSingleNode("following-sibling::td/a");
                if (img != null)
                
                    Console.WriteLine(img.InnerHtml);
                
            
        
    

【讨论】:

@_Darin Dimitrov:可以使用单个 XPath 表达式选择所需的文本节点(与托管 XPath 的编程语言无关)——请参阅我的答案。 @Dimitre Novatchev,哇,你是真正的 XPath 大师 :-) 这真的很棒。对我来说它看起来像中国人,但如果它有效,那就太好了。 @_Darin Dimitrov:是的,它有效,正如随附的基于 XSLT 的验证所证明的那样。虽然 XPath 优雅而强大,但它并不是特别困难。您可能对我多年前编写的 XPath Visualizer 感兴趣。它已经帮助成千上万的程序员以有趣的方式学习 XPath——只需使用不同的 XPath 表达式并逐步改进他们的结果。链接:huttar.net/dimitre/XPV/TopXML-XPV.html @Dimitre Novatchev,虽然看起来很有趣,但 XPath 并不是我在日常代码中使用的东西。由于我对它的无知,我宁愿避免它 :-) 话虽如此,我真的很佩服 XPath 大师,就像我佩服 Regex 大师一样。从来没有真正掌握这些概念。我对它们只有基本的了解,并且在需要时我更喜欢使用一些成熟的解析器来为我完成这项工作,并且避免编写特别是维护包含它们的代码。 顺便说一句,我刚刚测试了您的 XPath 表达式并且它们可以工作。向你致敬。

以上是关于XPath/HtmlAgilityPack:如何查找具有属性 (href) 特定值的元素 (a) 并查找相邻的表列?的主要内容,如果未能解决你的问题,请参考以下文章

如何查SQLSERVER2005的版本

WPF如何调用WCF对数据增删改查的服务

LADP如何查uid

如何查手机号是哪里的

PHP如何把前端用户的增删改查操做记录写进数据库表?

手机高德地图如何查两地距离