2020-02-24

XPathについて

XPathはXML文書の特定の部分を抜き出す構文。
htmlにも対応しているので
ウェブサイトの要素(見出し、画像、リンクなど)を表すことができる。


・簡単なhtmlの構造について

htmlは <タグ名></タグ名> で囲まれた様々なタグの入れ子構造になっている。
下記が基本構造(<!doctype html>は決まり文句)。
<!doctype html>
<html>
    <head>
        ...
    </head>
    <body>
        ...
    </body>
</html>

<body></body> の中に記載されたものがブラウザで表示される部分。

要素を追加する。
<!doctype html>
<html>
    <head>
        ...
    </head>
    <body>
        <div>
        </div>

        <div>
            <div>
                <p>
                </p>
            </div>

            <div>
            </div>
        </div>

        <h1>
        </h1>

        <a>
        </a>
    </body>
</html>

body の中にdivを2つ、h1、aを1つ 追加。
さらに 2つ目のdiv の中に divを2つ 追加。
さらに 1つ目のdiv の中に pを1つ 追加。

これをもとにXPathの表記を見てみる。


・XPathの絶対パス表記

XPathは / で区切りながらタグ名を記載していく。
h1 の絶対パス表記
/html/body/h1
a の絶対パス表記
/html/body/a

同じ段落に同じタグ名がある場合は [ ] に番号を書いて指定する。
番号は上から1始まり。
p の絶対パス表記
/html/body/div[2]/div[1]/p


・XPathの相対パス表記

// を使って間のタグを省略できる。
ワイルドカードのような使い方。
h1 の相対パス表記
//h1
p の相対パス表記
//p

今回の例のhtmlにはdivが複数あるため、相対パスで1つを特定できない。
//div (この場合4つのdivが該当)


・タグの属性を使った表記

htmlのタグには classid などの属性が指定されている場合がある。
その属性をもとにXPathを表記できる。

htmlの例を変更する。
<!doctype html>
<html>
    <head>
        ...
    </head>
    <body>
        <div class="sample1">
            <div id="index1">
            </div>

            <div id="index2">
            </div>
        </div>

        <div class="sample2">
            <h1 id="index3">
            </h1>

            <h1 id="index4">
            </h1>
        </div>
    </body>
</html>


属性を指定するときは タグ名[@属性名=""] で指定する。
・classがsample1のdiv
//div[@class="sample1"]
・idがindex3のh1
//h1[@id="index3"]

* をワイルドカードとしてタグ名を指定できる。
・classがsample2のタグ
//*[@class="sample2"]

contains を使って属性の値の一部だけでの指定もできる。
・idにindexを含むh1
//h1[contains(@id,"index")] (この場合<h1 id="index3">と<h1 id="index4">が該当)


・タグ内のテキストを使った表記

タグの中に記載されているテキストを指定できる。

htmlの例を変更する。
<!doctype html>
<html>
    <head>
        ...
    </head>
    <body>
        <div id="野菜">
            <ul>
                <li>人参</li>
                <li>ジャガイモ</li>
                <li>大根</li>
                <li>白菜</li>
            </ul>
        </div>

        <div id="果物">
            <ul>
                <li>リンゴ</li>
                <li>ブドウ</li>
                <li>梨</li>
                <li>いちご</li>
            </ul>
        </div>
    </body>
</html>


属性を指定したときの@属性名の代わりに text() と記載。
・テキストがジャガイモのli
//li[text()="ジャガイモ"]
・テキストが梨のタグ
//*[text()="梨"]

contains も同様に使える。
・テキストに根が含まれるタグ
//*[contains(text(),"根")]


・特定のタグからの相対表記

あるタグを基準にして1つ上の階層のタグ、同じ階層の1つ下のタグなど、
相対的な表記もできる。
一つ上の階層のタグ場合は parent を使い /parent::タグ名 のように表記。

・テキストがジャガイモのliの1つ上のタグ
//li[text()="ジャガイモ"]/parent::* (この場合<div id="野菜">の中の<ul>が該当)
・テキストが梨のタグと同じ階層の1つ上のli
//*[text()="梨"]/preceding-sibling::li (この場合<li>ブドウ</li>が該当)

相対表記(一部)
parent - 1つ上の階層
child - 1つ下の階層
preceding-sibling - 同じ階層の1つ上
following-sibling - 同じ階層の1つ下
preceding - 同じ階層の上にある全て
following - 同じ階層の下にある全て

0 件のコメント:

コメントを投稿