Html Agility Pack:DescendantsOrSelf()不返回HTML元素

时间:2010-06-16 17:20:10

标签: parsing asp.net html-agility-pack

我有一些HTML,例如:

<%@ Page Title="About Us" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="ContentManagedTargetPage.aspx.cs" Inherits="xxx.ContentManagedTargetPage" %>
<%@ Register TagPrefix="CxCMS" Namespace="xxx.ContentManagement.ASPNET.UI" Assembly="xxx.ContentManagement.ASPNET" %>
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2>
        Content Managed
    </h2>
    <p>
        Put content here.
        [<CxCMS:ContentManagedPlaceHolder Key="keyThingy" runat="server" />]
    </p>
</asp:Content>

我想找到CxCMS的所有实例:ContentManagedPlaceHolder元素。

我正在使用HTML Agility Pack,这似乎是最合适的。

然而,尽管查看[微薄]文档,但我无法使用我的代码。

我希望以下方法有效:

string searchForElement = "CxCMS:ContentManagedPlaceHolder";
IEnumerable<HtmlNode> contentPlaceHolderHtmlNodes = HtmlDocument.DocumentNode.Descendants(searchForElement);
int count = contentPlaceHolderHtmlNodes.Count();                

但我一无所获。

如果我更改为DescendantsOrSelf,我会返回文档节点“#document” - 这是不正确的:

string searchForElement = "CxCMS:ContentManagedPlaceHolder";
IEnumerable<HtmlNode> contentPlaceHolderHtmlNodes = HtmlDocument.DocumentNode.DescendantsOrSelf(searchForElement);
int count = contentPlaceHolderHtmlNodes.Count();                

我也尝试过使用LINQ:

string searchForElement = "CxCMS:ContentManagedPlaceHolder";
IEnumerable<HtmlNode> contentPlaceHolderHtmlNodes = HtmlDocument.DocumentNode.DescendantsOrSelf().Where(q=>q.Name==searchForElement);
int count = contentPlaceHolderHtmlNodes.Count();                

由于这两种方法都不起作用,我转而使用SelectNodes,而不是:

string searchForElement = "CxCMS:ContentManagedPlaceHolder";
string xPath="//"+searchForElement // "//CxCMS:ContentManagedPlaceHolder"
var nodes= HtmlDocument.DocumentNode.SelectNodes(xPath);

这只会引发异常:“需要命名空间管理器或XsltContext。此查询具有前缀,变量或用户定义的函数。”我找不到向HtmlDocument对象添加命名空间管理的任何方法。

我想念的是什么? DescendantsOrSelf()方法在使用“标准”HTML标记时起作用,例如“p”,但不是我拥有的标记。当然应该有用吗? (它需要!)

2 个答案:

答案 0 :(得分:1)

像往常一样,我花了一个小时左右的时间玩,我问这个问题,并在几秒钟之后弄明白。

使用DescendantsOrSelf()进行搜索时,节点名称必须为小写。

答案 1 :(得分:0)

您的示例实际上是ASPX。如果您正在解析该页面的输出,那么<CxCMS:ContentManagedPlaceHolder Key="keyThingy" runat="server" />实际呈现为客户端上的内容是值得怀疑的。查看客户端上的html源代码,找到与<CxCMS:ContentManagedPlaceHolder Key="keyThingy" runat="server" />对应的输出代码,然后在HtmlDocument.DocumentNode.Descendants中使用这些代码。

另一方面,如果您正在解析ASPX源代码,则可能需要将输入调整为HtmlDocument.DocumentNode.Descendants以便HtmlAgilityPack识别它,但请记住ASPX!= html并且我不知道我认为构建HtmlAgilityPack是为了解析它。

编辑:在HtmlAgilityPack源代码中查看HtmlNode.cs,由于以下两个部分,看起来你需要小写是正确的:

    /// <summary>
    /// Gets or sets this node's name.
    /// </summary>
    public string Name
    {
        get
        {
            if (_name == null)
            {
                Name = _ownerdocument._text
                                     .Substring(_namestartindex, _namelength);
            }
            return _name != null ? _name.ToLower() : string.Empty;
        }
        set { _name = value; }
    }

    /// <summary>
    /// Get all descendant nodes with matching name
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public IEnumerable<HtmlNode> Descendants(string name)
    {
        foreach (HtmlNode node in Descendants())
            if (node.Name == name)
                yield return node;
    }

请注意_name.ToLower()的getter中的Nameif (node.Name == name)方法中区分大小写的Decendants。这与使用DescendantsAndSelfElementElements方法的检查相同。