2010-06-16 8 views
0

J'ai quelques HTML, par exemple:Html Agility Paquet: DescendantsOrSelf() ne pas retourner l'élément 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> 

Et je veux trouver toutes les instances des CxCMS: élément ContentManagedPlaceHolder. J'utilise HTML Agility Pack, qui semble le meilleur ajustement.

Cependant, malgré l'examen de la documentation [maigre], je n'arrive pas à faire fonctionner mon code.

je me attends à ce qui suit au travail:

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

Mais je reçoivent rien en retour.

Si je change de DescendantsOrSelf, je reviens le nœud du document, "#document" - ce qui est incorrect:

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

J'ai aussi essayé d'utiliser LINQ:

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

Comme aucun de ces méthodes de travail, je suis passé à l'aide de SelectNodes, à la place:

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

Cela vient de jeter l'exception: "Namespace Manager ou XsltContext nécessaire. Cette requête a un préfixe, une variable, ou une fonction définie par l'utilisateur. "Je ne trouve aucun moyen d'ajouter la gestion de l'espace de noms à l'objet HtmlDocument

Qu'est-ce qui me manque, ici? La méthode DescendantsOrSelf() fonctionne si en utilisant une balise HTML "standard", comme "p", mais pas celle que j'ai, ça devrait marcher? (Il faut!)

Répondre

1

Comme d'habitude je passe une heure à jouer, je pose la question et je figure dehors secondes après.

Lors de la recherche à l'aide DescendantsOrSelf(), le nom du nœud doit être en minuscules.

0

Votre exemple est en fait ASPX. Si vous analysez la sortie de cette page, il est douteux que <CxCMS:ContentManagedPlaceHolder Key="keyThingy" runat="server" /> rende réellement cela du côté du client. Regardez la source html sur le client, trouvez les balises de sortie qui correspondent au <CxCMS:ContentManagedPlaceHolder Key="keyThingy" runat="server" />, puis utilisez celles du HtmlDocument.DocumentNode.Descendants. D'autre part, si vous analysez la source ASPX, vous devrez peut-être modifier votre entrée à HtmlDocument.DocumentNode.Descendants pour que le HtmlAgilityPack le reconnaisse, mais gardez à l'esprit que ASPX! = Html et je ne pense pas que le HtmlAgilityPack est construit pour l'analyser.

Edit: En regardant à travers HtmlNode.cs dans le code source de HtmlAgilityPack, il semble que vous avez raison sur ce besoin d'être en minuscules en raison des deux sections suivantes:

/// <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; } 
    } 

et

/// <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; 
    } 

Notez le _name.ToLower() dans le getter pour Name et la casse if (node.Name == name) dans la méthode Decendants.C'est le même contrôle utilisé les méthodes DescendantsAndSelf, Element et Elements.

+0

Oui, je travaille avec la source ASPX. Cela semble fonctionner dans les tests que j'ai fait jusqu'ici, après avoir trouvé la chose en minuscules! Merci. –