specter

Latest version: 1.1.3
mbjarland 2018-03-12T16:19:59.000152Z

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 not

mbjarland 2018-03-12T16:20:45.000186Z

don't need a complete answer, just need to understand which navigator to use in a case like this

mbjarland 2018-03-12T16:23:06.000183Z

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

mbjarland 2018-03-12T16:30:34.000440Z

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)

nathanmarz 2018-03-12T17:07:09.000794Z

@mbjarland you can capture more structure with this:

(defdynamicnav tags-traversal [& tags]
  (mapcat (fn [t] [ALL (tag? t)] tags))
  )

nathanmarz 2018-03-12T17:07:38.000585Z

and then do (select [(tags-traversal :body :table :tr) ...] data)

mbjarland 2018-03-12T19:26:43.000251Z

@nathanmarz : ) for once I wasn't far off then! Thanks, that is indeed cleaner

nathanmarz 2018-03-12T20:12:39.000126Z

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

nathanmarz 2018-03-12T20:13:13.000616Z

adding pred to return of tag? increases performance by avoiding a runtime conversion from function to navigator

nathanmarz 2018-03-12T20:13:55.000507Z

the late-resolved-fn call in tags-traversal allows that dynamicnav to handle dynamic parameters correctly (e.g. (tags-traversal :html some-local))

mbjarland 2018-03-12T20:15:06.000699Z

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

mbjarland 2018-03-12T20:40:05.000298Z

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

nathanmarz 2018-03-12T21:07:59.000547Z

@mbjarland do you know the index before the select happens?

mbjarland 2018-03-12T22:05:34.000406Z

yes

mbjarland 2018-03-12T22:05:39.000068Z

index is fixed

mbjarland 2018-03-12T22:05:54.000367Z

essentially it’s (rest (rest coll))

nathanmarz 2018-03-12T22:42:02.000364Z

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