This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-07-24
Channels
- # aleph (3)
- # beginners (17)
- # boot (8)
- # cider (61)
- # cljdoc (13)
- # cljs-dev (2)
- # clojure (66)
- # clojure-boston (1)
- # clojure-italy (4)
- # clojure-nl (7)
- # clojure-russia (7)
- # clojure-spec (19)
- # clojure-uk (80)
- # clojurescript (73)
- # core-async (4)
- # cursive (6)
- # data-science (1)
- # datomic (33)
- # docs (13)
- # emacs (17)
- # figwheel-main (28)
- # fulcro (12)
- # graphql (1)
- # jobs (3)
- # leiningen (4)
- # luminus (1)
- # off-topic (1)
- # parinfer (1)
- # pedestal (46)
- # protorepl (3)
- # re-frame (30)
- # reagent (47)
- # reitit (10)
- # ring (1)
- # shadow-cljs (94)
- # spacemacs (12)
- # specter (16)
- # tools-deps (6)
- # uncomplicate (1)
- # vim (9)
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
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
if I restructure the response as a nested map (assuming no dupes) {:TwilioResponse {:Call {:AnsweredBy nil :PriceUnit ["USD"] ...}}
I'd be done with a (get-in [:TwilioResponse :Call]])
, which I can do with with a few functions, but I'm hoping this can be cleanly done with a Specter select and XML zippers.
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?
if I restructure the response as a nested map (assuming no dupes) {:TwilioResponse {:Call {:AnsweredBy nil :PriceUnit ["USD"] ...}}
I'd be done with a (get-in [:TwilioResponse :Call]])
, which I can do with with a few functions, but I'm hoping this can be cleanly done with a Specter select and XML zippers.
@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)
yes, thanks @nathanmarz! š exactly right after a call to (into {} ...)
(assume no duplicate tags).
Is there a cleaner way to "walk" the XML tree {:tag .. :content ...}
layout so that {:tag :x :content :y}
becomes [:x :y]
or {:x :y}
?
yes, thanks @nathanmarz! š exactly right after a call to (into {} ...)
(assume no duplicate tags).
Is there a cleaner way to "walk" the XML tree {:tag .. :content ...}
layout so that {:tag :x :content :y}
becomes [:x :y]
or {:x :y}
?
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)
Would a recursive-path
walker be cleaner for transforming the general {:tag :content [{:tag ... :content [...]]}
shape returned by clojure.xml/parse
in general, then selecting a simpler nested path from there?
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)
Would a recursive-path
walker be cleaner for transforming the general {:tag :content [{:tag ... :content [...]]}
shape returned by clojure.xml/parse
in general, then selecting a simpler nested path from there?
if you want to maintain the general structure, then yes