【问题标题】:Filter element nodes in XML with Clojure zippers使用 Clojure 拉链过滤 XML 中的元素节点
【发布时间】:2018-05-08 14:49:43
【问题描述】:

如何使用 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 clojure


    【解决方案1】:

    我认为这与一般 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")
    

    【讨论】:

      【解决方案2】:

      您可以使用the Tupelo library 执行此操作,它使用clojure.data.xmltagsoup 解析器提供XML 解析:

      (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"]])))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多