2016-09-18 57 views
1

我走的是html/xml数据结构。我使用clojure.zip来穿过它。一旦找到我想要的节点(修剪),我找不到一种方法来删除所有的孩子和正确的节点。Clojure XML拉链走路和修剪

例子:

比方说,我有这样的树(表示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] 

应该最终导致字符串中的所有的<article><h1><img href=\"some-url\"></img> some-text</h1></article>

+0

你可以利用https://clojuredocs.org/clojure.zip/remove去除节点和相关的子树用它。 – Grav

+0

@Grav它删除节点,但似乎并没有删除与之相关的子树。 – nha

+0

(即使它的确如此,在我的示例中,A不是D的子树的一部分) – nha

回答

2

杉杉,我会修改你的任务通过以下方式:

目标是找到一些节点,然后从它的父母中删除它,并将其删除。

换句话说这样,cut功能可以很容易地与clojure.zip/edit帮助母公司实现的:

(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 "]}]}]}]} 
+0

今晚我会仔细看看,但看起来不错,谢谢! – nha

+0

我试图在另一个例子中(在我编辑的问题),它似乎并没有工作:''' ( - > HTML ZIP/ZML-ZIP 拉链/下 ZIP /右 ZIP /下 ZIP /向下 zip/down zip/right cut zip/root);; AA和BB仍然存在''' – nha

+0

但是'AA'和'BB'不是'some-text'的父节点('h1')的子节点,它们是父节点的兄弟节点的子节点。 – leetwinski