3

我发现 xml-> 的用法非常令人困惑。我已经阅读了文档和示例,但不知道如何获取 xml 文档的嵌套节点。

假设以下 xml 在拉链中(来自 xml-zip):

<html>
 <body>
  <div class='one'>
    <div class='two'></div>
  </div>
 </body>
</html>

我正在尝试使用 class='two' 返回 div。

我期待这个工作:

(xml-> z :html :body :div :div)

或这个:

(xml-> z :html :body :div (attr= :class "two"))

有点像 CSS 选择器。

但它只返回第一级,并且不会向下搜索树。

我能让它工作的唯一方法是:

(xml-> z :html :body :div children leftmost?)

那是我应该做的吗?

我开始使用 xml-> 的全部原因是为了方便并避免上下左右导航拉链。如果 xml-> 无法获得嵌套节点,那么我看不到 clojure.zip 上的值。

谢谢。

4

2 回答 2

1

两个连续:div匹配同一个节点。你应该下来的。而且我相信您已经忘记使用zip/node.

(ns reagenttest.sample
    (:require 
              [clojure.zip :as zip]
              [clojure.data.zip.xml :as data-zip]))
(let [s "..."
      doc (xml/parse (java.io.ByteArrayInputStream. (.getBytes s)))]
(prn (data-zip/xml-> (zip/xml-zip doc) :html :body :div zip/down (data-zip/attr= :class "two") zip/node)))

或者,如果您对以下内容不满意,可以使用自定义抽象xml->

(defn xml->find [loc & path]
    (let [new-path (conj (vec (butlast (interleave path (repeat zip/down)))) zip/node)]
        (apply (partial data-zip/xml-> loc) new-path)))

现在你可以这样做:

(xml->find z :html :body :div :div)
(xml->find z :html :body :div (data-zip/attr= :class "two"))
于 2017-06-20T20:19:18.727 回答
0

tupelo.forest 您可以使用Tupelo library解决此问题。forest包含用于搜索和操作数据树的函数。这就像使用类固醇的 Enlive。这是您的数据的解决方案:

(dotest
  (with-forest (new-forest)
    (let [xml-str         "<html>
                             <body>
                               <div class='one'>
                                 <div class='two'></div>
                               </div>
                             </body>
                           </html>"

          enlive-tree     (->> xml-str
                            java.io.StringReader.
                            en-html/xml-resource
                            only)
          root-hid        (add-tree-enlive enlive-tree)

          ; Removing whitespace nodes is optional; just done to keep things neat
          blank-leaf-hid? (fn [hid] (ts/whitespace? (hid->value hid))) ; whitespace pred fn
          blank-leaf-hids (keep-if blank-leaf-hid? (all-leaf-hids)) ; find whitespace nodes
          >>              (apply remove-hid blank-leaf-hids) ; delete whitespace nodes found

          ; Can search for inner `div` 2 ways
          result-1        (find-paths root-hid [:html :body :div :div]) ; explicit path from root
          result-2        (find-paths root-hid [:** {:class "two"}]) ; wildcard path that ends in :class "two"
    ]
       (is= result-1 result-2) ; both searches return the same path
       (is= (hid->bush root-hid)
         [{:tag :html}
          [{:tag :body}
           [{:class "one", :tag :div}
            [{:class "two", :tag :div}]]]])
      (is=
        (format-paths result-1)
        (format-paths result-2)
        [[{:tag :html}
          [{:tag :body}
           [{:class "one", :tag :div}
            [{:class "two", :tag :div}]]]]])

       (is (val= (hid->elem (last (only result-1)))
             {:attrs {:class "two", :tag :div}, :kids []})))))

单元测试森林示例演示文件中有许多示例。

于 2017-06-20T22:15:58.327 回答