Robin Munn
unread,May 4, 2013, 9:53:40 AM5/4/13Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
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)"?