LINQ to XPath 拡張 (Descendants(), Elements())

HtmlAgilityPack(HAP)は主にXPathを用いたノード探索に強みを持つHTMLパーサですが、C#におけるLINQ(Language Integrated Query)スタイルでのノード探索も可能です。これに関連してよく使われるのが Descendants()Elements() といった拡張メソッドです。これらは 「LINQ to XPath 拡張」 として、直感的かつ型安全なノード探索を提供します。


1. Descendants() の概要

Descendants()指定された名前のすべての子孫ノード(再帰的) を取得するメソッドです。

構文

csharp
var nodes = document.DocumentNode.Descendants("div");

意味

  • HTMLドキュメント全体から <div> タグのすべての子孫要素を取得。

  • XPathでいうと、"//div" に相当。

特徴

  • ノード階層を再帰的にたどる。

  • 属性フィルタを追加することも可能(LINQのWhere()を併用)。

csharp
var links = document.DocumentNode .Descendants("a") .Where(node => node.Attributes["href"] != null) .ToList();

→ すべての <a href="..."> タグを抽出。


2. Elements() の概要

Elements()現在のノードの直下の子要素のみ を取得するメソッドです(再帰しない)。

構文

csharp
var directChildren = parentNode.Elements("li");

意味

  • 親ノードの直下にある <li> タグだけを対象とする。

  • XPathでいうと、"./li" に相当。

特徴

  • 再帰的に探索はしない(直下のみ)。

  • 属性条件付きでフィルタできる。

csharp
var listItems = ulNode.Elements("li") .Where(node => node.InnerText.Contains("C#")) .ToList();

<ul> 直下にある <li> のうち、テキストに「C#」を含むものを抽出。


3. Descendants()Elements() の使い分け

メソッド 探索範囲 XPath相当 用途例
Descendants() 全ての子孫(再帰) //tag 任意階層からの抽出
Elements() 直下の子ノードのみ ./tag 特定ノードの直接の子要素のみ

4. 注意点

  • Descendants()Elements()HtmlNode に対して拡張メソッドとして利用されます。

  • あくまで「HTML構造に沿ったLINQ的処理」を提供するものであり、正確なHTML構文の知識があるとより活用しやすくなります。

  • 属性のフィルタや内部テキストの条件を併用する場合、.Where().Select() をLINQで組み合わせて記述します。


まとめ

HtmlAgilityPackの Descendants() および Elements() は、XPathと同様の目的をLINQスタイルで達成できる便利な拡張です。XPathの構文に不慣れな場合や、よりC#らしいコードで記述したい場合に特に有効です。

必要に応じて、FirstOrDefault()SingleOrDefault() を併用することで、1件だけの抽出処理も簡潔に記述できます。

ChatGPT4o 生成日:2025/06/23