2

CSSセレクターに一致する要素についてApacheBatikDOMにクエリを実行したいと思います。

Batikは、次のブラウザDOMメソッドのいずれかに代わるものを提供しますか?

4

1 に答える 1

2

OK、これが私がまとめた解決策です。Java ではなく Clojure で書かれていますが、重要な点は次のとおりです。

  1. org.apache.batik.css.engine.sac.CSSConditionFactory をインスタンス化します
  2. org.apache.batik.css.parser.Parser をインスタンス化する
  3. Parser.parseSelectors を呼び出す
  4. org.apache.batik.dom.traversal.TraversalSupport.createNodeIterator を呼び出す
  5. NodeFilter で、解析された SelectorList を反復処理し、ExtendedSelector.match を呼び出します。
  6. イテレータから返された最初のノードを条件付きでスキップします (常にトラバーサル ルートです)。
(def ^:private condition-factory
  (CSSConditionFactory. nil "class" nil "id"))

(defn- parse-selector [selector]
  (let [parser (Parser.)]
    (doto parser
      (.setSelectorFactory CSSSelectorFactory/INSTANCE)
      (.setConditionFactory condition-factory))
    (.parseSelectors parser selector)))

(defn- matches?
  ([selector element] (matches? selector element ""))
  ([selector element pseudo]
   (let [length (.getLength selector)]
     (loop [i 0]
       (if (< i length)
         (if (.. selector (item i) (match element pseudo))
           true
           (recur (inc i)))
         false)))))

(defn selection-seq [root selector]
  (let [selector (parse-selector selector)
        iterator (.createNodeIterator (TraversalSupport.)
                   (.getOwnerDocument root)
                   root
                   NodeFilter/SHOW_ELEMENT
                   (reify NodeFilter
                     (acceptNode [_ element]
                       (if (matches? selector element)
                         NodeFilter/FILTER_ACCEPT
                         NodeFilter/FILTER_REJECT)))
                   false)
        node-seq ((fn step []
                    (lazy-seq
                      (when-let [node (.nextNode iterator)]
                        (cons node (step))))))]
    ;; Iterator always returns the reference node, so match it.
    (when-let [node (first node-seq)]
      (if (matches? selector (first node-seq))
        node-seq
        (next node-seq)))))
于 2013-01-18T23:23:48.187 に答える