2

我想在 Apache Batik DOM 中查询与 CSS 选择器匹配的元素。

Batik 是否提供以下任何浏览器 DOM 方法的替代方法?

4

1 回答 1

2

好的,这是我设法放在一起的解决方案。它是用 Clojure 而不是 Java 编写的,但重要的部分是:

  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 回答