anyone ever seen an error like this before at compile time? java.lang.StackOverflowError, compiling:(com/rpl/specter/util_macros.clj:61:29
I’m seeing it when using Specter in Datomic Ions
scratch that. It appears to be a side-effect of a dependencies problem
I'm learning Specter and trying to parse an XML response I got from Twilio. I'm not super-familiar with Clojure zippers in general, but I suspect it'll be cleaner & faster with Specter. I've stumbled onto the S/collect
function, but I'm having a hard time fetching "sibling" nodes when dealing with a shape like this:
{:tag :TwilioResponse,
:attrs nil,
:content [{:tag :Call,
:attrs nil,
:content [{:tag :AnsweredBy, :attrs nil, :content nil}
{:tag :PriceUnit, :attrs nil, :content ["USD"]}
{:tag :From, :attrs nil, :content ["+2787..."]}
{:tag :To, :attrs nil, :content ["+2776..."]}
}]}]}
How do I ask Specter to collect the deepest :tag
and :content
values in the structure, but only if the parent :tag
is :TwilioResponse, with a :Call
parent under :tag?
I managed to get what I want by doing the following, but it feels like there must be a cleaner way to refer to parents/siblings:
(->> my-parsed-xml (S/select-one [(S/collect-one :content S/FIRST :content)
:tag (S/pred= :TwilioResponse)])
first
(map (juxt :tag (comp first :content))))
@petrus not totally clear on what you want
you want nodes in this tree that have a parent tag of :Call
and grandparent tag of :TwilioResponse
?
can this substructure exist at any depth, or only starting at the root?
@petrus is this what you're looking for?
(select-first
[#(= :TwilioResponse (:tag %))
:content
ALL
#(= :Call (:tag %))
:content]
data)
or this?
(select
[#(= :TwilioResponse (:tag %))
:content
ALL
#(= :Call (:tag %))
:content
ALL
(collect-one :tag)
:content
(view first)]
data)
you can factor out any composition of navigators as its own navigator
e.g.
(def tag+content
(path
(collect-one :tag)
:content
(view first)))
(select
[#(= :TwilioResponse (:tag %))
:content
ALL
#(= :Call (:tag %))
:content
ALL
tag+content]
data)
if you want to navigate to the pair, you can use subselect + multi-path
(select
[#(= :TwilioResponse (:tag %))
:content
ALL
#(= :Call (:tag %))
:content
ALL
(subselect (multi-path :tag [:content (view first)]))]
data)
if you want to maintain the general structure, then yes