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

问题描述 投票:3回答:2

如何使用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
2个回答
6
投票

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

0
投票

您可以使用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
© www.soinside.com 2019 - 2024. All rights reserved.