2

I have a question of how to perform a select * style "query" for xml files in clojure. Say, I have this XML, that you can get from this URL http://api.eventful.com/rest/events/search?app_key=4H4Vff4PdrTGp3vV&keywords=music&location=Belgrade&date=Future (if I paste it here it doesn't look good)

I want to get a vector of maps (map with tags as keys and its values), for all the repeating "rows" in the XML. So that every map is a event in this example XML. I can parse it, and make a zipper structure of it. Also I know how to do it using struct maps, but I want a more general solution, for any given xml, and maybe some starting tags from which to start. What I want is opposite from this Simple Clojure XML edit. Any idea would be great!

Thanks!

Community
  • 1
  • 1
Vesna
  • 345
  • 2
  • 11
  • I know there is a clojure library for xpath, but I thought that I could do it using zippers...no luck though.... – Vesna Sep 14 '12 at 18:38

1 Answers1

2

You should take a look at enlive. It will transform XML into different list/map based structure and allow queries against it.

For example to select all the events you'd have to do the following:

(require '[net.cgrand.enlive-html :as html])
(def data (html/xml-resource "your.xml"))
(html/select data [:events])

To get all the event titles:

(select data [:even :title :*])

I haven't used it for a couple of months so I'm a little rusty. But there's a lot of material online.

EDIT:

You can actually use zippers to navigate data structure created by xml-resource. Here's an example where I look for any link with word bank in it and walk up from it to get its parent node.

(require [net.cgrand.enlive-html :as html])
(require [net.cgrand.xml :as xml])
(require [clojure.zip :as z])

(map
  (comp z/node z/up)
  (@#'html/zip-select-nodes*
   (map xml/xml-zip (html/html-resource page2))
   (@#'html/automaton
    [:a (html/re-pred #".*[Bb]ank.*")])))

I have to use @#' as functions zip-select-nodes* and automaton are namespace private.

Ivan Koblik
  • 4,285
  • 1
  • 30
  • 33
  • Well its author describes it as: "[Enlive is an extraction and transformation library for HTML and XML documents written in Clojure.](https://github.com/cgrand/enlive/wiki)" – Ivan Koblik Sep 14 '12 at 18:45
  • Zippers are cool, you can actually use them with Enlive, but it is a little hidden. I'll add to my answer info about it! – Ivan Koblik Sep 14 '12 at 18:51
  • I was thinking something more like this: (->> (en-html/select xml-doc [:holiday]) (map en-html/text) (partition 2) (map #(zipmap [:name :month] %))). it works fine with this xml International Lefthanders Day August 13 Rover's birthday October 12 ... but not with mine. I can't get to select anything from my feed. – Vesna Sep 20 '12 at 21:16