This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-05-24
Channels
- # announcements (1)
- # babashka (86)
- # beginners (75)
- # boot-dev (1)
- # cljdoc (18)
- # cljs-dev (1)
- # cljsrn (67)
- # clojure (127)
- # clojure-australia (1)
- # clojure-dev (2)
- # clojure-europe (9)
- # clojure-nl (2)
- # clojure-serbia (2)
- # clojure-spec (11)
- # clojure-uk (14)
- # clojurescript (17)
- # code-reviews (4)
- # conjure (37)
- # core-async (11)
- # datomic (21)
- # emacs (1)
- # helix (36)
- # jobs (6)
- # malli (1)
- # meander (20)
- # re-frame (13)
- # reagent (49)
- # remote-jobs (11)
- # rum (1)
- # sci (1)
- # shadow-cljs (29)
- # sql (17)
- # vim (2)
Hi, I’m trying to process some clojure.xml output and i’m obviously doing something wrong ;).
I need to recursively walk through the seqs on the :`content` key, and have mappings that differ based on the :tag
value. My example is complicated, so will just use the example from data.xml
;;
#clojure.data.xml.Element{:tag :foo,
:attrs {},
:content (#clojure.data.xml.Element{:tag :bar,
:attrs {},
:content (#clojure.data.xml.Element{:tag :baz,
:attrs {},
:content ("The baz value")})})}
; based on the recursive strategy example, tried a few variants of the following
(def convert-log4j-tag
(m*/rewrite
{:tag (m/pred #(= % :foo) ?tag)
:content [(m/cata !content) ...]}
{:tag (m/app (comp str/capitalize name) ?tag)
:content [!content ...]}
{:tag (m/pred #(= % :bar) ?tag)
:content [(m/cata !content) ...]}
{:tag (m/app (comp str/capitalize name) ?tag)
:content [!content ...]}
...
It looks like you need to add a “catch all” clause for non map objects. If the m/cata
fails, so will the whole clause. Add
?x ?x
at the end.ah sweet, let me give this a try. still figuring stuff out, but this is really cool s@#$ lol.
ok, ugh, that didn’t work. it seems to just return the input unchanged
(def x (xml/parse-str "<foo><bar><baz>The baz value</baz></bar></foo>"))
(def convert-foobar
(m*/rewrite
{:tag (m/and :foo ?tag)
:attrs ?attrs
:content [(m/cata !content) ...]}
{:tag (m/app (comp str/capitalize name) ?tag)
:attrs ?attrs
:content [!content ...]}
{:tag (m/and :bar ?tag)
:attrs ?attrs
:content [(m/cata !content) ...]}
{:tag (m/app (comp str/capitalize name) ?tag)
:attrs ?attrs
:content [!content ...]}
{:tag (m/and :baz ?tag)
:attrs ?attrs
:content [(m/cata !content) ...]}
{:tag (m/app (comp str/capitalize name) ?tag)
:attrs ?attrs
:content [!content ...]}
?x ?x))
(def convert-foobars
(m*/bottom-up ; tried top-down, etc as well
(m*/attempt convert-foobar)))
(convert-foobars x)
@U380J7PAQ I took a minute to try this out on my local machine and would able to get it to work. The reason it was not rewriting was due to the :content [,,,]
portion of the match, namely the [,,,]
. Meander treats [,,,]
and (,,,)
as representing vectors and seqs respectively. In this case the value of :content
is a seq so we have two options: use the (,,,)
notation or use (m/seqable ,,,)
. In this case I might suggest using the latter:
(def convert-foobar
(m*/rewrite
{:tag (m/and :foo ?tag)
:attrs ?attrs
:content (m/seqable (m/cata !content) ...)}
{:tag (m/app (comp str/capitalize name) ?tag)
:attrs ?attrs
:content (m/seqable !content ...)}
{:tag (m/and :bar ?tag)
:attrs ?attrs
:content (m/seqable (m/cata !content) ...)}
{:tag (m/app (comp str/capitalize name) ?tag)
:attrs ?attrs
:content (m/seqable !content ...)}
{:tag (m/and :baz ?tag)
:attrs ?attrs
:content (m/seqable (m/cata !content) ...)}
{:tag (m/app (comp str/capitalize name) ?tag)
:attrs ?attrs
:content (m/seqable !content ...)}
?x ?x))
Using your example input I was able get the output
{:tag "Foo",
:attrs {},
:content
({:tag :bar,
:attrs {},
:content ({:tag "Baz", :attrs {}, :content ("The baz value")})})}
Note you do not have to use m/seqable
on the right, you can use the vector notation, etc.
so another question on this. in my actual code, for some parent tags, there are possibly some children on the :content key, whose data I want to pull into the parent. and in those cases, I don’t want those children in the output so just in xml:
<foo>
<param name="a" value="b"/>
<bar>...</bar>
...
; converts to
<Foo a="b">
<Bar>...<Bar>
About to start playing with it but any tips would be appreciated 😉{:tag :foo
:content (m/seqable (m/or {:tag :bar :as !bar} _)}
{:tag "Foo"
:content [{:tag "Bar" & !bar} ...]}
ok so I see how this one handles the omission of params, so that seems straightforward, so hmm I guess m/or can match on params use that in :attrs on the RHS, while the check on the RHS in content will keep the params out of the new :content. cool, gonna try that when i get back to my desk