ARR-XML
This is an arrowized, mostly lazy, xml package following the clojure.data.xml representation. [:tag [:tag1 {:attr1 “hello”} “content”]]
which is delivered as a seq through the arrow chain.
There is heavy reliance on the accumulators and filters of arrows-extra
(use 'conduit.core 'arrows.core 'arrows-extra.core 'clojure.data.xml)
The library allows constructs such as:
(a-comp (arr-select-elem “tag1”) (a-all (a-comp (arr-select-elem “tag2”) arr-characters) (a-comp (arr-select-elem “tag3”) arr-attributes) ) )
The parser is lazy, and outputs the clojure.data.xml representation.
(def-arr arr-stream-to-xml-seq [instream]
":: InputStream -> [XML]"
(source-seq instream :coalescing false)
)
First, we switch by tag name - pass-through until the tag is encountered. Then send subtags down the channel. We implement this with arr-toggle-switch-inclusive
(defn arr-switch-elem [default-channel name channel & more]
(arr-toggle-switch-inclusive (if (empty? more) default-channel (apply (partial arr-switch-elem default-channel) more)) (fn[input] (and (= (:name input) name) (= (:type input) :start-element)))
(fn[input] (and (= (:name input) name) (= (:type input) :end-element)))
channel
)
)
Test
(conduit-map (a-comp arr-stream-to-xml-seq (disperse (arr-switch-elem pass-through :there (a-arr (fn [input] (str "ch1" input)))))) [(java.io.StringReader. "<hello><there><this>is</this></there><your><friendly>newsagent</friendly></your></hello>")])
Here we switch into a nil. The reason we don’t switch into a block is so that we can use this with a-all. This means that non matching elements fire as a nil
(defn arr-select-elem [name]
(arr-switch-elem (a-arr (fn [input] nil)) name pass-through)
)
Recursive Use: (arr-select-path :first :second :third) returns <third>
(defn arr-select-path [name & more]
(a-comp (arr-select-elem name) (if (empty? more) pass-through (apply arr-select-path more)))
)
Test:
(doall (conduit-map (a-comp arr-stream-to-xml-seq (disperse (arr-select-path :there :this))) [(java.io.StringReader. "<hello><nice>one</nice><there><this>is</this></there><your><friendly>newsagent</friendly></your></hello>")]))
Select out the attributes map from start elements
(def-proc arr-attributes [input]
(let [attrs (:attrs input)]
(if attrs [attrs] [])
)
)
Fire a seq of characters from the seq of xml
(def-proc arr-characters [input]
(let [chars (:str input)]
(if chars [chars] [])
)
)
(ns arr-xml.core)
<<use-conduit>>
<<arr-switch-elem>>
<<arr-select-elem>>
<<arr-select-path>>
<<arr-attributes>>
<<arr-characters>>
<<arr-parsers>>
(defproject exchange "1.0.0"
:description "See arr-xml.org"
:dependencies [[org.clojure/clojure "1.4.0"]
[net.intensivesystems/conduit "0.8.1"]
[arrows-extra "1.0.0"]
[org.clojure/data.xml "0.0.6"]
])