web-dev-qa-db-ja.com

HtmlAgilityPackおよびノー​​ドとサブノードの選択

誰かが私を助けてくれることを願っています。

この例のような複数のdivを含むHTMLドキュメントがあるとしましょう:

<div class="search_hit">

    <span prop="name">Richard Winchester</span>
    <span prop="company">Kodak</span>
    <span prop="street">Arlington Road 1</span>

</div>
<div class="search_hit">

    <span prop="name">Ted Mosby</span>
    <span prop="company">HP</span>
    <span prop="street">Arlington Road 2</span>

</div>

HtmlAgilityPackを使用してHTMLドキュメントを取得しています。私が知る必要があるのは、各「search_hit」-divのスパンをどのように取得できるかです。

私の最初の考えは次のようなものでした:

foreach (HtmlAgilityPack.HtmlNode node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']"))
{
     foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("//span[@prop]"))
     {

     }
}

各divは、プロパティとして含まれるスパンを持つオブジェクトである必要があります。 I. e。

public class Record
    {
        public string Name { get; set; }
        public string company { get; set; }
        public string street { get; set; }
    }

そして、このリストはそれから満たされます:

public List<Record> Results = new List<Record>();

しかし、私が使用しているXPATHは、必要なようにサブノードで検索を行いません。ドキュメント全体を何度も検索するようになっています。

つまり、ページ全体のスパンを取得するだけの方法で既に動作しているということです。しかし、その後、私はスパンとdivの間に関係がありません。意味:どのスパンがどのdivに関連しているかはもうわかりません。

誰かが解決策を知っていますか?私はすでに、私が今完全に混乱していることをいじくり回しました:)

どんな助けも大歓迎です!

40
The Jack

次は私のために働く。重要な点は、「SelectNodes」への2番目の呼び出しでドットを追加するようBeniBelaが指摘したとおりです。

List<Record> lstRecords=new List<Record>();
foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']"))
{
  Record record=new Record();
  foreach (HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
  {
    string attributeValue = node2.GetAttributeValue("prop", "");
    if (attributeValue == "name")
    {
      record.Name = node2.InnerText;
    }
    else if (attributeValue == "company")
    {
      record.company = node2.InnerText;
    }
    else if (attributeValue == "street")
    {
      record.street = node2.InnerText;
    }
  }
  lstRecords.Add(record);
}
34
shriek

//を使用すると、ドキュメントから検索が始まります。

.//を使用して、現在のノードからすべてを検索します

 foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes(".//span[@prop]"))

または、直接の子のみを検索するには、プレフィックスを完全に削除します。

 foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("span[@prop]"))
53
BeniBela

まず、これを見てください:Html Agility Pack-サブノードの選択の問題

質問に対する完全に機能するソリューションは次のとおりです。

IList<Record> results = new List<Record>();
foreach (var node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']")) {
    var record = new Record();
    record.Name = node.SelectSingleNode(".//span[@prop='name']").InnerText;
    record.company = node.SelectSingleNode(".//span[@prop='company']").InnerText;
    record.street = node.SelectSingleNode(".//span[@prop='street']").InnerText;
    results.Add(record);
}

私が指摘した質問を読むと、./span[@prop='name']は、これらのspanノードがdivノードの(直接の)子であるため、まったく同じです。


spanノードにこれらのprop属性がなく、表示される順序に応じてそれらを割り当てる場合は、以下を実行できます。

foreach (var node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']")) {
    var spanNodes = node.SelectNodes("./span");
    var record = new Record();
    record.Name = spanNodes[0].InnerText;
    record.company = spanNodes[1].InnerText;
    record.street = spanNodes[2].InnerText;
    results.Add(record);
}
3
Oscar Mederos

私の恥:)

みなさんは正しかったです。

問題が見つかりました。このNullReferenceExceptionが私を悩ませ続けたので、私はそれを詳細に見るためにより多くの時間を費やしました。これらすべてのdivの間に、同じ「class = 'search-hit'」属性を持つが、内部にスパンのないdivが1つありました。そのため、2番目のループでエラーが発生します。

foreach (HtmlAgilityPack.HtmlNode node in doc.DocumentNode.SelectNodes("//span[@prop]/ancestor::div[@class='search_hit']"))
   {
        Record rec = new Record();
        foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
           {
           }
           rList.Results.Add(rec);
   }

上記のコードは機能しています。

お時間をいただきありがとうございます!

2
The Jack

私はそれを使用しました。クラス変換ID

  HtmlNodeCollection nodes = dokuman.DocumentNode.SelectNodes("//div[@id='search_hit']//span[@prop]");


            for (int i = 0; i < nodes .Count; i++)
        {
            var record = new Record();


                record.Name = links[i].InnerText;   results.Add(record);  }
0
ibrahim ozboluk