Недавно я добавил 2 синтаксических анализатора XML в библиотеку Tupelo , один из которых основан на clojure.data.xml
, а другой - tagsoup
.В обоих случаях я удаляю пробельные узлы по умолчанию.Вот оперативная функция :
(defn enlive-remove-whitespace
"Removes whilespace strings from Enlive data :content vectors."
[item]
(if (and (map? item) ; Enlive data parsed from XML may has raw strings (esp. whitespace) embedded in it
(contains-key? item :tag)) ; when parsing html, may get non-enlive nodes like {:type :comment, :data "..."}
(let [content-new (cond-it-> (:content item)
(or (nil? it) (empty? it)) []
:then (drop-if (fn [arg]
(and (string? arg)
(ts/whitespace? arg))) it)
:then (mapv enlive-remove-whitespace it))]
(glue item {:content content-new}))
item))
Используется так для tupelo.parse.xml
:
(s/defn parse ; #todo fix docstring
([xml-input] (parse xml-input sax-parse-fn))
([xml-input parse-fn]
(enlive-remove-whitespace
(enlive-normalize
(parse-raw xml-input parse-fn)))))
Итак, вы видите, что вы можете использовать Функция parse-raw
, если вы не хотите нормализовать или обрезать пробелы в результирующих данных в формате Enlive.
Доступны аналогичные варианты для parse
и parse-raw
в пространстве имен tupelo.parse.tagsoup
.
Примеры использования можно увидеть в тесте ns :
(def xml-str "<foo>
<name>John</name>
<address>1 hacker way</address>
<phone></phone>
<school>
<name>Joe</name>
<state>CA</state>
<type>FOOBAR</type>
</school>
<college>
<name>mit</name>
<address></address>
<state>Denial</state>
</college>
</foo> ")
(def enlive-tree-normalized-nonblank
{:tag :foo,
:attrs {},
:content [{:tag :name, :attrs {}, :content ["John"]}
{:tag :address, :attrs {}, :content ["1 hacker way"]}
{:tag :phone, :attrs {}, :content []}
{:tag :school,
:attrs {},
:content [{:tag :name, :attrs {}, :content ["Joe"]}
{:tag :state, :attrs {}, :content ["CA"]}
{:tag :type, :attrs {}, :content ["FOOBAR"]}]}
{:tag :college,
:attrs {},
:content [{:tag :name, :attrs {}, :content ["mit"]}
{:tag :address, :attrs {}, :content []}
{:tag :state, :attrs {}, :content ["Denial"]}]}]})
с результатом
(dotest
(let [xml-data (xml/parse (ts/string->stream xml-str))
tagsoup-data (tagsoup/parse (ts/string->stream xml-str))]
(is= enlive-tree-normalized-nonblank xml-data)
(is= enlive-tree-normalized-nonblank tagsoup-data) ))