使用Clojure拉链过滤XML中的元素节点

Jin*_*arz 3 xml clojure

如何使用Clojure拉链过滤XML中的文本节点?例如,您可能有一个印刷精美的XML文档,该文档将元素节点与包含空格的文本节点交织在一起:

(def doc
  "<?xml version=\"1.0\"?>
  <root>
    <a>1</a>
    <b>2</b>
  </root>")
Run Code Online (Sandbox Code Playgroud)

如果您要检索的子项的内容,则root可以执行以下操作:

(require '[clojure.data.xml :as xml]
         '[clojure.zip :as zip]
         '[clojure.data.zip :as zf]
         '[clojure.data.zip.xml :as zip-xml])

(-> doc
    xml/parse-str
    zip/xml-zip
    (zip-xml/xml-> :root zf/children zip-xml/text))
Run Code Online (Sandbox Code Playgroud)

但是,这将返回(" " "1" " " "2" " "),包括空格。

如何过滤拉链,以便仅选择元素节点?

我想出了这个。

(def filter-elements (comp (partial filter (comp xml/element? zip/node)) zf/children))

(-> doc
    xml/parse-str
    zip/xml-zip
    (zip-xml/xml-> :root filter-elements zip-xml/text))
; => ("1" "2")
Run Code Online (Sandbox Code Playgroud)

我怀疑它不必要地复杂,因此我正在寻找更好的解决方案。

glt*_*lts 6

我认为这与确定哪个空白有意义和哪个空白无关的一般XML解析问题有关。例如,请参见以下问答:为什么我会获得额外的文本节点作为根节点的子节点?

我检查并发现data.xml确实支持通过option跳过空格:skip-whitespace。它是未记录的()。

因此,最好在解析阶段解决此问题。

(-> doc
    (xml/parse-str :skip-whitespace true)
    zip/xml-zip
    (zip-xml/xml-> :root zf/children zip-xml/text))
; => ("1" "2")
Run Code Online (Sandbox Code Playgroud)