Clojure XML 拉链行走和修剪
Clojure XML zipper walk and prune
我正在走 html/xml 数据结构。我使用 clojure.zip
遍历它。一旦找到我想要 cut
(修剪)的节点,我就无法找到删除所有 children 和正确节点的方法。
示例:
假设我有这棵树(代表 html):
(def tree [:p "F"
[:p "G" [:p "I" [:p "H"]]]
[:p "B"
[:p
"D"
[:p "E"]
[:p "C"]]
[:p "A"]]])
我解析它,xml-zip
它,在行走的某个时刻,我最终到达节点 "D",我想在该处剪切。我现在需要 return 没有 "E"、"C" (children) 和 "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>
首先,我将按以下方式重新表述您的任务:
目标是找到某个节点,然后从它的 parent.
中删除它及其右侧的所有内容
这样说,cut
函数可以在 clojure.zip/edit
的帮助下很容易地实现,因为 parent:
(defn cut [loc]
(when-let [parent (z/up loc)]
(z/edit parent #(z/make-node loc % (z/lefts loc)))))
所以,如上所述,我们编辑 loc
的父节点,创建它的新节点,只保留 loc
左侧的子节点。
注意,那里有 when-let
宏,如果传递的位置没有父级(意味着它是拉链的根),可以避免空指针异常
现在测试:
让我们尝试删除包含 ["I"]
:
的 p
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 "]}]}]}]}
我正在走 html/xml 数据结构。我使用 clojure.zip
遍历它。一旦找到我想要 cut
(修剪)的节点,我就无法找到删除所有 children 和正确节点的方法。
示例:
假设我有这棵树(代表 html):
(def tree [:p "F"
[:p "G" [:p "I" [:p "H"]]]
[:p "B"
[:p
"D"
[:p "E"]
[:p "C"]]
[:p "A"]]])
我解析它,xml-zip
它,在行走的某个时刻,我最终到达节点 "D",我想在该处剪切。我现在需要 return 没有 "E"、"C" (children) 和 "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>
首先,我将按以下方式重新表述您的任务:
目标是找到某个节点,然后从它的 parent.
中删除它及其右侧的所有内容这样说,cut
函数可以在 clojure.zip/edit
的帮助下很容易地实现,因为 parent:
(defn cut [loc]
(when-let [parent (z/up loc)]
(z/edit parent #(z/make-node loc % (z/lefts loc)))))
所以,如上所述,我们编辑 loc
的父节点,创建它的新节点,只保留 loc
左侧的子节点。
注意,那里有 when-let
宏,如果传递的位置没有父级(意味着它是拉链的根),可以避免空指针异常
现在测试:
让我们尝试删除包含 ["I"]
:
p
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 "]}]}]}]}