このブログは、旧・はてなダイアリー「檜山正幸のキマイラ飼育記 メモ編」(http://d.hatena.ne.jp/m-hiyama-memo/)のデータを移行・保存したものであり、今後(2019年1月以降)更新の予定はありません。

今後の更新は、新しいブログ http://m-hiyama-memo.hatenablog.com/ で行います。

検索範囲(軸)、リミット、Next-sibling範囲

情報抽出(extraction)の検索範囲とは、基本的にノード集合(空集合のときもある)だが、次の構造を持つ。

  1. 侵入的順序構造:パターンマッチングの失敗時と、侵入的パターンによるマッチングの成功時に「次」を決めるために使用する順序。線形順序である。
  2. 非侵入的順序構造:非侵入的パターンによるマッチングの成功時に「次」を決めるために使用する順序。部分順序でよい。

侵入的順序と非侵入的順序が異なるのは、Descendant範囲(軸)だけで、他のタイプの検索範囲では侵入的順序と非侵入的順序は一致する。

検索範囲に含まれるノードの個数(集合の基数)をサイズと呼ぶ(XPathの用語)。パターンマッチングが成功できる最大数をリミットと呼ぶ。

今までは、リミット=サイズ という前提だったので、特にリミットを意識する必要はなかった。しかし、Next-sibling範囲ではリミットとサイズは異なることがある。リミットは常に1(1回を越えて成功はできない、高々1回の成功まで)であるが、Next-sibling範囲のサイズは1を超えることがある。

このような現象が起きるのは、(text), (pi-or-comment), (node) というCSSにはないセレクターを導入したためである。これらの特別なセレクターと'+'コンビネータの折り合いを付けるためには、リミットとサイズが違うことを認める必要がある。

次のパターンを考える。

<div#this>
 + <p>$:text</>
</>

HTMLとして:

<div id="this">...</div> <p>...</p>

Next-sibling範囲を、DOMツリー上のホントの隣接ノードにすると、このマッチングは失敗する。なぜから、div#this の隣接ノードは空白を含むテキストノードだから。同様に次も失敗する。

<div id="this">...</div><!-- --><p>...</p>

これは直感にあわない。この問題を回避するために、Next-sibling範囲を次のように決める。

  1. コンテキストノード(基点)から弟(following)方向に兄弟をたどって、はじめて出現した要素ノードまでをNext-sibling範囲とする。複数の非要素ノード(pi, comment, text)が含まれるかもしれない。
  2. 要素が出現する前に兄弟リストが終わった場合は、最後の兄弟までをNext-sibling範囲とする。このとき、要素ノードは含まれないが、非要素ノード(pi, comment, text)が含まれるかもしれない。
  3. コンテキストノード自体が兄弟の最後のノードのときは、Next-sibling範囲は空となる。

次の例で、div#this に対するNext-sibling範囲のサイズは4となる。要素ノードが1個、非要素ノードが3個である。

<section>
  <div id="this">...</div> <!-- --> <p>...</p>
</section>

Next-sibling範囲のリミットはサイズに関わらず1なので、マッチング成功は高々1回。

もう一度検索範囲の構造をまとめると:

  1. ノード集合: 空集合でもよい。
  2. 侵入的順序構造: 線形順序。
  3. 非侵入的順序構造: Descendant範囲以外では侵入的順序と同じ。
  4. リミット:Next-sibling範囲以外ではサイズと同じ(自明、無制約)。Next-sibling範囲では常に1。