Version 29 (modified by amachang, 4 years ago)

--

XPath から CSS Selector への変換を真剣に検討するページ

XPath を IE8 で querySelector 出来るセレクタに変換する方法を考えよう」

HTML で使用することに特化していい

XPath から要素を取得する過程で使う目的

ブレスト

出来る系

//aaa//bbb//ccc
=> aaa bbb ccc

/aaa/bbb/ccc
=> html > bbb > ccc (ルートは html と決まっているから妥協)

id("hoge")
=> #hoge

id("hoge") | //aaa[@hoge="fuga"]
=> #hoge, aaa[hoge="fuga"]

//aaa/*[1]
=> aaa > *:first-child

//aaa[contains(@hoge, 'fuga')]
=> aaa[hoge*="fuga"]

//aaa[ends-with(@hoge, 'fuga')]
=> aaa[hoge$="fuga"]

(//aaa | //bbb)/ccc
=> aaa > ccc, bbb > ccc

//aaa[@hoge=1+1]
=> aaa[hoge="2"]   (パース時に定数を計算しているので)

出来ない系

aaa/bbb/ccc
=> child 軸から始まる (一時的に id を付けてやるのはどうか、パフォーマンス気になる)

./aaa/bbb/ccc
=> self 軸

..
=> parent 系の軸や兄要素にさかのぼる系

//aaa[.="hoge"]
=> 条件部に属性以外の条件 (ただし、条件部の結果にコンテキストの概念が必要ない場合は、実行時に変換できる)

//aaa[@hoge=count(.//bbb//ccc)]
=> ネストしている (パース時に .//bbb//ccc をセレクタに直して実行し、 .//bbb//ccc の値が確定したら全体をセレクタに直して実行するのはどうか)

IE8 で対応するセレクタ

http://msdn.microsoft.com/en-us/library/cc351024%28VS.85%29.aspx

  • Simple Selector
    • .value
    • #value
    • E
    • *
    • [att=val]
    • [att]
    • [att|=val]
    • [att~=val]
    • [att^=val]
    • [att*=val]
    • [att$=val]
  • Combinator
    • E + F
    • E > F
    • E F
    • E ~ F

方法を考える

走り書きで

方法 1

  1. XPath をパースする
    1. 定数に出来るところはする
  2. 構文木を変換できる部分木を探す
    1. 式を上から順に走査 (再帰 a)
      1. PathExpr? だった場合
        1. FilterExpr? を変換する
          1. id(Expr) の場合
            1. Expr を変換する
              1. 定数の場合
                1. "#hogehoge" を生成して次へ
              2. その他の場合
                1. null を返す
            2. id(Expr) が持つ Predicate を走査する
              1. 処理 c が CSS Selector を返す場合は
                1. ここまで連結してきた CSS Selector に、ここで返ってきた CSS Selector を連結して続ける
              2. その他の場合
                1. ここまでしか解析できていないという情報と、ここまで連結してきた CSS Selector を返す
            3. 続く NodeTest? を変換する
              1. 処理 b
          2. context-node() (JavaScript?-XPath 独自の概念) の場合
          3. root-node() (JavaScript?-XPath 独自の概念) の場合
            1. 次の Step を先読み
            2. context-node() の次の Step が child 軸で、 NodeTest?NameTest? で、 NameTest? が html, head, body のいずれかである場合
        2. NodeTest? を変換する (処理 b)
        3. Predicate を変換する (処理 c)
          1. Predicate が定数で boolean 型, string 型の場合
            1. (パース時点で、消滅させるべきなので、ここに来たらエラーにする)
          2. Predicate が定数で boolean 型, string 型の場合
            1. これ以上変換できないので、
      2. UnionExpr? がだった場合
        1. すべての PathExpr? が CSS Selector を返した場合で、その CSS Selector がカンマを含まない場合
          1. すべての CSS Selector をカンマでつないで返す
        2. そのほかの場合
          1. 何も返さない
      3. そのほかの場合
        1. 何も返さない
  3. ---------------------------
    1. 上から順に変換する
      1. Step は以下の様に変換する
        1. (FIXME) Predicate も含め、すべて変換できる Step は
        2. (FIXME) 属性軸以外の軸で始まる LocationPath? がオペランドとして現れた場合、それを含む式は変換できない
      2. id 関数は以下の様に変換する
      3. UnionExpr? は以下のように変換する
  4. 実行する