Fork me on GitHub
#specter
<
2018-03-12
>
mbjarland16:03:59

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

mbjarland16:03:45

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

mbjarland16:03:06

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

mbjarland16:03:34

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)

nathanmarz17:03:09

@mbjarland you can capture more structure with this:

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

nathanmarz17:03:38

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

mbjarland19:03:43

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

nathanmarz20:03:39

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

nathanmarz20:03:13

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

nathanmarz20:03:55

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

mbjarland20:03:06

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

mbjarland20:03:05

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

nathanmarz21:03:59

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

mbjarland22:03:39

index is fixed

mbjarland22:03:54

essentially it’s (rest (rest coll))

nathanmarz22:03:02

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