meander

All things about https://github.com/noprompt/meander Need help and no one responded? Feel free to ping @U5K8NTHEZ
eoliphant 2021-05-24T14:41:19.004300Z

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 ...]}
...

eoliphant 2021-05-25T15:02:47.007700Z

ah hell it was just that? lol ok great thanks!

1😂
eoliphant 2021-05-26T14:43:30.008100Z

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 😉

noprompt 2021-05-26T16:05:35.008400Z

You want to keep the <bar> and discard the <param>

noprompt 2021-05-26T19:02:23.008600Z

I apologize, my previous message meant to have a question mark at the end of it. 😛

noprompt 2021-05-26T19:03:37.008800Z

{:tag :foo 
 :content (m/seqable (m/or {:tag :bar :as !bar} _)}
{:tag "Foo"
 :content [{:tag "Bar" & !bar} ...]}

eoliphant 2021-05-26T19:35:32.009Z

yes, i want to collect some info from params into Foo, then drop params

eoliphant 2021-05-26T19:39:00.009200Z

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

noprompt 2021-05-27T16:25:25.009400Z

Following up on this; how can I help?

noprompt 2021-05-27T16:25:45.009600Z

Or, rather, do you still need some help?

eoliphant 2021-05-27T17:26:55.009800Z

hi, actually haven’t gotten to it yet today 🙂. thanks for checking in will let you know

noprompt 2021-05-27T17:50:38.010Z

No worries. Drop me a line whenever.

eoliphant 2021-05-24T14:46:05.005600Z

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

noprompt 2021-05-24T16:10:58.005700Z

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.

noprompt 2021-05-24T16:11:29.005900Z

Also, you can write

(m/and :foo ?tag)
instead of
(m/pred #(= % :foo) ?tag)

1👍
eoliphant 2021-05-24T18:25:06.006400Z

ah sweet, let me give this a try. still figuring stuff out, but this is really cool s@#$ lol.

eoliphant 2021-05-24T18:42:06.006600Z

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)

noprompt 2021-05-24T21:16:58.006800Z

@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))

1👍1
noprompt 2021-05-24T21:20:58.007100Z

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")})})}

noprompt 2021-05-24T21:21:36.007300Z

Note you do not have to use m/seqable on the right, you can use the vector notation, etc.