使用Clojure删除特定的XML节点 [英] Remove specific XML nodes using Clojure
问题描述
我具有以下XML结构:
I have the following XML structure:
(def xmlstr
"<ROOT>
<Items>
<Item><Type>A</Type><Note>AA</Note></Item>
<Item><Type>B</Type><Note>BB</Note></Item>
<Item><Type>C</Type><Note>CC</Note></Item>
<Item><Type>A</Type><Note>AA</Note></Item>
</Items>
</ROOT>")
在其中要删除任何具有B型或C型的项目。结果应为类似:
where I want to remove any Item, if it has a Type B or C. The result should be something like:
<ROOT>
<Items>
<Item><Type>A</Type><Note>AA</Note></Item>
<Item><Type>A</Type><Note>AA</Note></Item>
</Items>
</ROOT>
我发现使用data.xml和data.xml.zip查询此类结构非常简单,例如:
I've found it pretty trivial to query such structures using data.xml and data.xml.zip, e.g:
;; lein try org.clojure/data.xml org.clojure/data.zip
(def xmldoc (clojure.data.xml/parse-str xmlstr))
(def zipxml (clojure.zip/xml-zip xmldoc))
(clojure.data.zip.xml/xml-> zipxml :Items :Item [:Type "A"] :Note clojure.data.zip.xml/text)
;; => ("AA" "AA")
,但是没有找到类似的声明性功能来删除/编辑子级
but didn't find similar declarative features for removing/editing children.
推荐答案
Clojure标准API提供了方便的函数来处理XML和其他树结构。可以使用 clojure.walk <进行深度优先遍历来删除(叶)节点/ a>:
The Clojure standard APIs provide convenient functions for manipulating XML and other tree structures. Removing (leaf) nodes can be done on depth-first traversal using clojure.walk:
(require '[clojure.xml :as xml]
'[clojure.walk :as walk])
(def xmlstr
"<ROOT>
<Items>
<Item><Type>A</Type><Note>AA</Note></Item>
<Item><Type>B</Type><Note>BB</Note></Item>
<Item><Type>C</Type><Note>CC</Note></Item>
<Item><Type>A</Type><Note>AA</Note></Item>
</Items>
</ROOT>")
(def xmldoc (xml/parse (java.io.ByteArrayInputStream. (.getBytes xmlstr))))
(defn tag-matches [item tag]
(= (:tag item) tag))
(defn content-matches [item to-match]
((into #{} to-match)
(apply str (:content item))))
(defn match-criteria [item to-match]
(some #(and (tag-matches % :Type)
(content-matches % to-match))
(:content item)))
(defn mk-xml-walker [& to-remove]
(fn [form]
(if (and (vector? form)
(some #(tag-matches % :Item) form))
(filter (complement #(match-criteria % to-remove)) form)
form)))
(xml/emit (walk/postwalk (mk-xml-walker "B" "C") xmldoc))
对于神奇的一线客,您可能还想看看 Specter ,它为处理嵌套数据结构(例如XML)提供了非常简洁的语法。
For magical one-liners, you may also want to check out Specter which provides a very concise syntax for manipulating nested data structures, like XML.
这篇关于使用Clojure删除特定的XML节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!