(defn safety-xpath-call
  "to call xpath safely"
  [xpath xml]
  (try
    (xpath/$x xpath xml)
    (catch org.xml.sax.SAXException saxe (handle-exception saxe))))

(defn get-result
   "to extract text from a xml-string"
   [xpath xml-string key-list]
   (for [line (safety-xpath-call xpath xml-string)]
     (reduce get line key-list)))

(defn- get-query-word
  "to extract query word from a xml-string"
  [xml-string]
  (first (get-result "(/*)[1]" xml-string '(:attrs :query))))

(defn extract-dictionary
  "to extract word and entries from a xml-string of thesaurus"
  [xml-string]
  {:word (get-query-word xml-string)
   :entries
     (flatten
       (for [pos (get-result "//partofspeech" xml-string '(:attrs :pos))]
         (for [line (get-result (str "//partofspeech[@pos=\"" pos "\"]/defset/def") xml-string '(:text))] {:pos pos :text line})))})

(defn extract-example
  "to extract word and entries from a xml-string of example"
  [xml-string]
  {:word (get-query-word xml-string)
   :entries (get-result "//example" xml-string '(:text))})

(defn extract-random
  "to extract word from a xml-string of random"
  [xml-string site]
  {:word (first (get-result (str "//" site  "/random_entry") xml-string '(:text)))})

(defn extract-spelling
  "to extract word and entries from a xml-string of spelling"
  [xml-string]
  {:word (get-query-word xml-string)
   :entries (get-result "//suggestion" xml-string '(:text))})