1

我正在走一个 html/xml 数据结构。我使用clojure.zip. 一旦找到我想要cut(修剪)的节点,我就找不到删除所有子节点和右节点的方法。

例子:

假设我有这棵树(代表 html):

(def tree [:p "F"
           [:p "G" [:p "I" [:p "H"]]]
           [:p "B"
            [:p
             "D"
             [:p "E"]
             [:p "C"]]
            [:p "A"]]])

我解析它,xml-zip它,在行走时的某个时刻,我最终到达了节点“D”,我想在其中剪切。我现在需要返回没有“E”、“C”(子)和“D”的根。这些是此时使用时尚未访问的所有节点next

我将如何删除这些节点?

注意:如果这不可行,我也欢迎一种复制拉链的方法cut

示例数据:这是我对上述树的解析数据,我称之为xml-zip

{:tag :html, :attrs nil, :content [{:tag :head, :attrs nil, :content nil} {:tag :body, :attrs nil, :content [{:tag :p, :attrs nil, :content ["F"]} {:tag :p, :attrs nil, :content ["G"]} {:tag :p, :attrs nil, :content ["I"]} {:tag :p, :attrs nil, :content ["H"]} {:tag :p, :attrs nil, :content nil} {:tag :p, :attrs nil, :content nil} {:tag :p, :attrs nil, :content ["B"]} {:tag :p, :attrs nil, :content ["D"]} {:tag :p, :attrs nil, :content ["E"]} {:tag :p, :attrs nil, :content ["C"]} {:tag :p, :attrs nil, :content nil} {:tag :p, :attrs nil, :content ["A"]} {:tag :p, :attrs nil, :content nil} {:tag :p, :attrs nil, :content nil}]}]}

我开始像这样遍历它以获取内容:

(-> parsed (z/xml-zip)
           (z/down) ;head
           (z/right) ; body
           (z/down) ; content
           )

另一个例子:

以下字符串:"<article><h1><img href=\"some-url\"></img> some-text <b>in bold</b></h1><ul><li> AA </li> <li>BB</li></ul></article>" 将为我提供以下地图:

[{:tag :html, :attrs nil, :content [{:tag :head, :attrs nil, :content nil} {:tag :body, :attrs nil, :content [{:tag :article, :attrs nil, :content [{:tag :h1, :attrs nil, :content [{:tag :img, :attrs {:href "some-url"}, :content nil} " some-text " {:tag :b, :attrs nil, :content ["in bold"]}]} {:tag :ul, :attrs nil, :content [{:tag :li, :attrs nil, :content [" AA "]} " " {:tag :li, :attrs nil, :content ["BB"]}]}]}]}]} nil]

在“some-text”切割时,它最终应该导致字符串 <article><h1><img href=\"some-url\"></img> some-text</h1></article>

4

1 回答 1

2

首先,我会改写你的任务如下:

目标是找到某个节点,然后从它的parent中删除它以及它右侧的所有内容。

这么说,这个cut功能可以在clojure.zip/editfor parent的帮助下轻松实现:

(defn cut [loc]
  (when-let [parent (z/up loc)]
    (z/edit parent #(z/make-node loc % (z/lefts loc)))))

所以,正如上面所说,我们编辑 的父loc节点,创建它的新节点,只保留 . 左边的子节点loc

请注意,那里有when-let宏,如果传递的位置没有父级(意味着它是拉链的根),则可以避免空指针异常

现在测试:

让我们尝试删除p包含["I"]

user> (-> html
          z/xml-zip
          z/down
          z/right
          z/down
          z/right
          z/right
          z/node)
;; {:tag :p, :attrs nil, :content ["I"]}

user> (-> html
          z/xml-zip
          z/down
          z/right
          z/down
          z/right
          z/right
          cut
          z/root)
;;{:tag :html, :attrs nil, 
;; :content [{:tag :head, :attrs nil, :content nil} 
;;           {:tag :body, :attrs nil, 
;;            :content [{:tag :p, :attrs nil, :content ["F"]} 
;;                      {:tag :p, :attrs nil, :content ["G"]}]}]}

正如预期的那样:从身体右侧(包括)的所有东西都I被移除了。

更新

根据更新,您要删除目标之一之后树中的所有节点。这有点棘手,因为它需要将所有节点的父节点更改为根节点。在这种情况下,cut函数可能如下所示:

(defn cut [loc]
  (loop [loc loc]
    (if-let [parent (z/up loc)]
      (recur
       (z/replace parent
                  (z/make-node loc
                               (z/node parent)
                               (drop-last (count (z/rights loc))
                                          (z/children parent)))))
      (z/node loc))))

测试:

user> (-> h2 
          z/xml-zip 
          z/down 
          z/right 
          z/down 
          z/down 
          z/down 
          z/right 
          cut)

;;{:tag :html, :attrs nil, 
;; :content [{:tag :head, :attrs nil, :content nil} 
;;           {:tag :body, :attrs nil, 
;;            :content [{:tag :article, :attrs nil, 
;;                       :content [{:tag :h1, :attrs nil, 
;;                                  :content [{:tag :img, :attrs {:href "some-url"}, :content nil} " some-text "]}]}]}]}
于 2016-09-19T15:48:53.910 回答