Skip to content

Instantly share code, notes, and snippets.

@classicrob
Forked from green-coder/html.clj
Created March 15, 2022 01:05
Show Gist options
  • Select an option

  • Save classicrob/81bbad07a99491cbae3445ba79c9b56a to your computer and use it in GitHub Desktop.

Select an option

Save classicrob/81bbad07a99491cbae3445ba79c9b56a to your computer and use it in GitHub Desktop.
Cross platform (CLJC) and hackable `html->hiccup` function.
(ns hiccdown.html
(:require [clojure.edn :as edn]
[instaparse.core :as insta :refer [defparser]]))
;; A cross-platform (CLJC) html->hiccup converter for Hiccdown's own needs.
;; For now, only used in the tests.
(defparser html-parser "
nodes = node*
<node> = text | open-close-tags | self-closing-tag
open-close-tags = opening-tag nodes closing-tag
opening-tag = <'<'> <spaces>? tag-name attributes? <spaces>? <'>'>
closing-tag = <'</'> tag-name <'>'>
self-closing-tag = <'<'> <spaces>? tag-name attributes? <spaces>? <'/>'>
tag-name = #'[^ </>]+'
attributes = (<spaces> attribute)+
attribute = attribute-name (<'='> attribute-value)?
<attribute-name> = #'[^ \t=]+'
<attribute-value> = #'[^ \t]+' | #'\"[^\"]*\"'
<text> = #'[^<]+'
spaces = #'[ \t]+'
")
(defn html->hiccup [html-str]
(->> (html-parser html-str)
(insta/transform {:nodes (fn [& nodes] nodes)
:open-close-tags (fn [opening-tag nodes _closing-tag]
(into opening-tag nodes))
:opening-tag (fn ([tag-name] [tag-name])
([tag-name attributes] [tag-name attributes]))
:self-closing-tag (fn ([tag-name] [tag-name])
([tag-name attributes] [tag-name attributes]))
:tag-name keyword
:attributes (fn [& attributes]
(into {} attributes))
:attribute (fn ([attribute-name]
[(keyword attribute-name) true])
([attribute-name attribute-value]
[(keyword attribute-name) (edn/read-string attribute-value)]))})))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment