Apache Batik中的querySelector

时间:2013-01-18 21:19:23

标签: css dom batik

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

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

1 个答案:

答案 0 :(得分: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. 有条件地跳过迭代器返回的第一个节点(它始终是遍历根)
  7. (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)))))