How do I select "clusters" of nodes?

108 views
Skip to first unread message

Robin Munn

unread,
May 4, 2013, 9:53:40 AM5/4/13
to enliv...@googlegroups.com
I'm writing some Clojure code using Enlive to process some XML documents that have a vague resemblance to HTML, but with some unique elements. The one that's giving me a lot of trouble right now is the <tab> element these documents contain, which is often used for things that should have been ordered lists. For example, there will be snippets like this:

<p class="Normal">Some text</p>
<p class="ListWithTabs">(a)<tab />First list item</p>
<p class="ListWithTabs">(b)<tab />Second list item</p>
<p class="ListWithTabs">(c)<tab />Third list item</p>
<p class="Normal">Some more text</p>
<p class="AnotherListStyle">1.<tab />Another list</p>
<p class="AnotherListStyle">2.<tab />With just two items</p>
<p class="Normal">Some final text</p>

My processing needs to turn this code into valid HTML, which means turning some of those <p> elements -- the ones that contain <tab> descendants -- into proper <li> elements (with an <ol> wrapped around the list). I could do that easily if I could somehow select "clusters" of elements. My first attempt was to write a selector like:

(use '[net.cgrand.enlive-html :as e])
(e/select [[:p (e/has [:tab])]])

This returns a list of five :p elements, which gives me all the elements I need to transform into <li> elements, but doesn't give me any information about how they were grouped in the original document. What I'd love to do is write a selector that would return something like:

[
  [{:tag :p, :content (... "First list item" ...)}
   {:tag :p, :content (... "Second list item" ...)}
   {:tag :p, :content (... "Third list item" ...)}
  ] ; Three items in first list
  [{:tag :p, :content (... "Another list" ...)}
   {:tag :p, :content (... "With just two items" ...)}
  ] ; Two items in second list
]

What would be the best way to "cluster" connected elements together like this? I've been able to write selectors like "first-of-tab-group" and "rest-of-tab-group", as follows:

(def first-of-tab-group [(e/has [:tab])
                         (e/left (complement (e/has [:tab])))])
(def rest-of-tab-group [(e/has [:tab])
                        (e/left (e/has [:tab]))])

But I'm not sure how to take the next step. How do I turn those two selectors into a "clustering" selector? In other words, how do I write a selector that says "Give me every element that matches first-of-tab-group, and for each element in the results, make all the elements that match rest-of-tab-group tag along with them in a single vector (or list)"?

Christophe Grand

unread,
May 5, 2013, 4:23:14 AM5/5/13
to enliv...@googlegroups.com
Hi,

Try {first-of-tab-group last-of-tab-group} as the selector – it's a range selector. 

HTH,

Christophe
--
You received this message because you are subscribed to the Google Groups "Enlive" group.
To unsubscribe from this group and stop receiving emails from it, send an email to enlive-clj+...@googlegroups.com.
To post to this group, send email to enliv...@googlegroups.com.
Visit this group at http://groups.google.com/group/enlive-clj?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 


--
On Clojure http://clj-me.cgrand.net/
Clojure Programming http://clojurebook.com
Training, Consulting & Contracting http://lambdanext.eu/

Reply all
Reply to author
Forward
0 new messages