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 ...]}
...
ah hell it was just that? lol ok great thanks!
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 😉You want to keep the <bar>
and discard the <param>
I apologize, my previous message meant to have a question mark at the end of it. 😛
{:tag :foo
:content (m/seqable (m/or {:tag :bar :as !bar} _)}
{:tag "Foo"
:content [{:tag "Bar" & !bar} ...]}
yes, i want to collect some info from params into Foo, then drop params
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
Following up on this; how can I help?
Or, rather, do you still need some help?
hi, actually haven’t gotten to it yet today 🙂. thanks for checking in will let you know
No worries. Drop me a line whenever.
but just haven’t been able to traverse ‘through’ content in any fashion. I’m either getting nil results or the whole thing back with no transformation applied, etc
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.Also, you can write
(m/and :foo ?tag)
instead of
(m/pred #(= % :foo) ?tag)
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)
@eoliphant 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.