如何使用Clojure拉链过滤XML中的文本节点?例如,您可能有一个漂亮的XML文档,它将元素节点与包含空格的文本节点交错:
(def doc
"<?xml version=\"1.0\"?>
<root>
<a>1</a>
<b>2</b>
</root>")
如果要检索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))
但是,这会返回(" " "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")
我怀疑它不必要地复杂,因此我正在寻找更好的解决方案。
我认为这涉及一般的XML解析问题,即决定哪些空白是有意义的,哪些不是。例如,请参阅此问答:Why am I getting extra text nodes as child nodes of root node?
我检查并发现data.xml确实支持通过选项:skip-whitespace
跳过空白。它虽然没有记载(source)。
所以最好在解析阶段解决这个问题。
(-> doc
(xml/parse-str :skip-whitespace true)
zip/xml-zip
(zip-xml/xml-> :root zf/children zip-xml/text))
; => ("1" "2")
您可以使用the Tupelo library执行此操作,clojure.data.xml
使用tagsoup
和(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test)
(:require
[tupelo.forest :as tf]
[tupelo.parse.tagsoup :as tagsoup]
[tupelo.string :as ts] ))
(dotest
(let [doc "<?xml version=\"1.0\"?>
<root>
<a>1</a>
<b>2</b>
</root>"
result-enlive (tagsoup/parse (ts/string->stream doc))
result-hiccup (tf/enlive->hiccup result-enlive)
]
(is= result-enlive
{:tag :root,
:attrs {},
:content
[{:tag :a, :attrs {}, :content ["1"]}
{:tag :b, :attrs {}, :content ["2"]}]})
(is= result-hiccup
[:root
[:a "1"]
[:b "2"]])))
解析器提供XML解析:
qazxswpoi