Skip to content

Instantly share code, notes, and snippets.

@bguthrie
Last active September 17, 2015 16:15
Show Gist options
  • Save bguthrie/a222e31ff4b6e0550def to your computer and use it in GitHub Desktop.
Save bguthrie/a222e31ff4b6e0550def to your computer and use it in GitHub Desktop.
An attempt to strongly-type an XML search function.
(ns xml.typed
(:require [clojure.xml :as xml]
[clojure.core.typed :as t])
(:import (clojure.lang Keyword)))
(t/defalias XmlNodeContent (t/U String XmlNode))
(t/defalias XmlNode
(t/HMap :mandatory {:tag Keyword
:content (t/ASeq XmlNodeContent)}
:optional {:attrs (t/Map Keyword String)}))
(t/ann clojure.xml/parse (t/All [[x :> InputStream]] [x -> XmlNode]))
(t/ann only-xml-node-children-of [XmlNode -> (t/ASeq XmlNode)])
(defn only-xml-node-children-of [root]
((t/inst filter XmlNodeContent XmlNode)
#(not (string? %))
(:content root)))
(t/ann child-named [XmlNode Keyword -> (t/Option XmlNode)])
(defn child-named [root name]
(let [children (only-xml-node-children-of root)]
(first
(filter
(t/fn [x :- XmlNode]
(= (:tag x) name))
children))))
(t/ann find-node [XmlNode (t/Seqable Keyword) -> (t/Option XmlNode)])
(defn find-node [root names]
(let [maybe-name (first names)]
(if (nil? maybe-name)
root
(when-let [child (child-named root maybe-name)]
(recur child (rest names))))))
(def some-xml
{:tag :body
:content
[{:tag :a
:attrs {:href "http://google.com"}
:content
[{:tag :h1
:content ["Hello, World"]}]}
]
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment