XPath のチュートリアル

このチュートリアルでは、 calibre の HTML ドキュメントの中から任意の部分を選択するために利用できる `XPath <https://en.wikipedia.org/wiki/XPath>`_というクエリ言語に関して軽く紹介します。XPath は広く使用されているる標準で、Google などで検索すると山ほどの情報が出てきます。しかしこのチュートリアルでは、構造化されていない HTML ドキュメントの中から章見出しを探す方法のような、電子書籍に関した特化した XPath の利用法に焦点を当てています。

タグ名で選択

選択の一番簡単な方法はタグを名前で選択することです。たとえば、ドキュメント内のすべての <h2> を選択したいとしましょう。そのための XPath は次のようにすればよいのです:

//h:h2        (Selects all <h2> tags)

プリフィックス //ドキュメント内の任意のレベルの検索 を意味します。<a> タグの中にある <span> タグを検索したいとしましょう。これを実現するには、次のようにします:

//h:a/h:span    (Selects <span> tags inside <a> tags)

ドキュメント内のある特定のレベルのタグを検索したい場合には、プリフィックスを変更します:

/h:body/h:div/h:p (Selects <p> tags that are children of <div> tags that are
             children of the <body> tag)

これは サンプル電子書籍 の中にある <p>XPath の使用を実演してみせるための非常に短い電子書籍です。</p> にのみマッチして、他の <p> タグ内のものにはマッチしません。上記の例では XHTML タグにマッチさせるために h: プリフィックスが必要です。なぜなら calibre は内部的にはすべてのコンテンツを XHTML で表現しているためです。XHTML においてタグには 名前空間が 存在し、h: が HTML タグの名前空間プレフィックスです。

では <h1> タグと <h2> タグの両方を選択したいとしましょう。これをするには 述語 と呼ばれる XPath の構造体が必要になります。述語 とはタグの選択に使用される単なるテストです。テストは自ずと強力であり、チュートリアルを進めるにつれて、より強力な使用例を目にするでしょう。述語はテストの式を角カッコで囲むことで作成します:

//*[name()='h1' or name()='h2']

この XPath 式にはいくつかの新しい機能があります。ひとつはワイルドカード * の使用です。これは すべてのタグにマッチ することを意味します。では、テスト式 name()='h1' or name()='h2' を見てみましょう。name()ビルトイン関数 の例です。これは単にタグの名前を評価します。したがってこれを使用することで、名前が h1 または h2 であるタグを選択できます。name() は名前空間を無視するため、h: プリフィックスは必要ありません。XPath にはいくつもの便利なビルトイン関数があります。このチュートリアルの中で、さらにいくつか紹介します。

属性で選択

属性に基づいてタグを選択するには、述語を使用する必要があります:

//*[@style]              (Select all tags that have a style attribute)
//*[@class="chapter"]    (Select all tags that have class="chapter")
//h:h1[@class="bookTitle"] (Select all h1 tags that have class="bookTitle")

ここでは @` 演算子がタグの属性を参照します。`XPath ビルトイン関数`_を使用すれば、属性値に対してさらに高度な比較を行うことができます。

タグの内容で選択

XPath を使えば、タグに含まれているテキストに基づいてタグを選択することもできます。これを行うのに一番よいのは、ビルトイン関数 re:test() を通じて正規表現の力を利用することです:

//h:h2[re:test(., 'chapter|section', 'i')] (Selects <h2> tags that contain the words chapter or
                                          section)

ここでは @ 演算子が属性を参照するのと同様に、. 演算子がタグの内容を参照します。

サンプル電子書籍

<html>
    <head>
        <title>A very short e-book</title>
        <meta name="charset" value="utf-8" />
    </head>
    <body>
        <h1 class="bookTitle">A very short e-book</h1>
        <p style="text-align:right">Written by Kovid Goyal</p>
        <div class="introduction">
            <p>A very short e-book to demonstrate the use of XPath.</p>
        </div>

        <h2 class="chapter">Chapter One</h2>
        <p>This is a truly fascinating chapter.</p>

        <h2 class="chapter">Chapter Two</h2>
        <p>A worthy continuation of a fine tradition.</p>
    </body>
</html>

XPath ビルトイン関数

name()

現在のタグの名前

contains()

contains(s1, s2) は s1 に s2 が含まれているときに true を返します。

re:test()

re:test(src, pattern, flags) は 文字列 src が正規表現 pattern にマッチしたとき true を返します。特に便利はフラグは i で、大文字と小文字を区別せずに比較するようになります。正規表現の構文に関しては、 regexp syntax がよい入門書となります。