How would I go about selecting a specific node in a vector of vectors structure like the following:
[:html
{}
[:body
{}
[:table
{}
[:tr {} [:th {:colspan "1", :rowspan "1"} "Task Name"] [:th {:colspan "1", :rowspan "1"} "Description"]]
[:tr
{}
[:td {:colspan "1", :rowspan "1"} [:a {:shape "rect", :href "Tasks/unpack.html"} "GUnzip/BUnzip2/UnXZ"]]
[:td {:colspan "1", :rowspan "1"} [:p {} "Expands a file packed using GZip, BZip2 or XZ."]]]
i.e. I would like to check the :href
value on the second to last row and if it matches a predicate, return the string on the last row. Mainly I'm confused in general about how to write paths against vectors with some kind of predicate logic for which paths to traverse and which to notdon't need a complete answer, just need to understand which navigator to use in a case like this
somehow traverse to the first elems of vectors in the structure and if they match (in order) :html
, :body
, :table
:tr
then check a predicate against the first :td
and collect string from the second :td
if predicate matches
ok figured out a solution, a tad ugly but it works:
(defn tag? [name]
(fn [vec]
(and (vector? vec) (= (first vec) name))))
and
(spctr/select
[spctr/ALL (tag? :body) spctr/ALL (tag? :table) spctr/ALL (tag? :tr) ... etc]
data)
@mbjarland you can capture more structure with this:
(defdynamicnav tags-traversal [& tags]
(mapcat (fn [t] [ALL (tag? t)] tags))
)
and then do (select [(tags-traversal :body :table :tr) ...] data)
@nathanmarz : ) for once I wasn't far off then! Thanks, that is indeed cleaner
@mbjarland btw, here's a better way to implement those:
(defn tag? [name]
(pred
(fn [vec]
(and (vector? vec) (= (first vec) name)))))
(defdynamicnav tags-traversal [& tags]
(let [late-tag? (late-resolved-fn tag?)]
(mapcat (fn [t] [ALL (late-tag? t)]) tags)
))
adding pred
to return of tag?
increases performance by avoiding a runtime conversion from function to navigator
the late-resolved-fn
call in tags-traversal
allows that dynamicnav to handle dynamic parameters correctly (e.g. (tags-traversal :html some-local)
)
ok well that brings us back to the normal cycle of “no there’s a much better way to do that” : ) many thanks, will noodle on this
ok last one…how would I select the “rest” of a vector starting at an index…`srange` and srange-dynamic
do not seem to do quite this from what I understand
@mbjarland do you know the index before the select
happens?
yes
index is fixed
essentially it’s (rest (rest coll))
@mbjarland is this what you need?
(defn subrest [i]
(srange-dynamic (fn [_] i) (fn [s] (count s))))
(transform (subrest 2) reverse [1 2 3 4 5 6])
;; => [1 2 6 5 4 3]