Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 75 lines (58 sloc) 2.054 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
(ns twoguys.html-selector
  (:require [clojure.zip :as zip])
  (:use [clojure.string :only (split)]
[clojure.contrib.core :only (.?.)]
[clojure.java.io :only (reader)])
  (:import [nu.validator.htmlparser.dom HtmlDocumentBuilder]
[org.w3c.dom Document Node]
[org.xml.sax InputSource]))

(defn build-document [file-name]
  (.parse (HtmlDocumentBuilder.) (InputSource. (reader file-name))))

(defn id-sel [document id]
  (let [id (.substring id 1)]
    (list (.getElementById document id))))

(defn nodelist-seq [node-list]
  (letfn [(internal [i]
(lazy-seq
(when (< i (.getLength node-list))
(cons (.item node-list i) (internal (inc i))))))]
    (internal 0)))

(defn dom-seq [root-node]
  (let [children (nodelist-seq (.getChildNodes root-node))]
    (lazy-cat
     children
     (when-not (empty? children)
       (mapcat dom-seq children)))))

(defn element-tagname [elt]
  (when (= Node/ELEMENT_NODE (.getNodeType elt))
    (.getNodeName elt)))

(defmulti element-sel (fn [node elt-name]
(condp instance? node
Document Document
Node)))

(defmethod element-sel Document [document elt-name]
  (nodelist-seq (.getElementsByTagName document elt-name)))

(defmethod element-sel Node [node elt-name]
  (filter #(= elt-name (element-tagname %)) (dom-seq node)))

(defn get-attribute [elt attr]
  (.?. elt getAttributes (getNamedItem attr) getValue))

(defn hasclass? [elt class]
  (when-let [class-attr (get-attribute elt "class")]
    (some #(= class %) (split class-attr #" "))))

(defn class-sel [node class]
  (filter #(hasclass? % (.substring class 1)) (dom-seq node)))

(defmulti compile-selector type)

(defmethod compile-selector clojure.lang.IFn [f]
  f)

(defmethod compile-selector String [s]
  (condp = (.charAt s 0)
      \# #(id-sel % s)
      \. #(class-sel % s)
      #(element-sel % s)))

(defn text-sel [node]
  (list (.getTextContent node)))

(defn flip [f]
  (fn [& args]
    (apply f (reverse args))))

(defn $ [node & selectors]
  (reduce (flip mapcat) [node] (map compile-selector selectors)))
Something went wrong with that request. Please try again.