有没有将HTML转换为hiccup结构的解析器?

8
我正在寻找一个能够反转Clojure Hiccup的函数。
因此,以下HTML代码:
   <html></html>
将被转换为:
[:html]

跟进@kotarak的回答,这对我现在起作用了:

(use 'net.cgrand.enlive-html)
(import 'java.io.StringReader)

(defn enlive->hiccup
   [el]
   (if-not (string? el)
     (->> (map enlive->hiccup (:content el))
       (concat [(:tag el) (:attrs el)])
       (keep identity)
       vec)
     el))

(defn html->enlive 
  [html]
  (first (html-resource (StringReader. html))))

(defn html->hiccup [html]
  (-> html
      html->enlive
      enlive->hiccup))

=> (html->hiccup "<html><body id='foo'>hello</body></html>")
[:html [:body {:id "foo"} "hello"]]

例如……如果我正在与一个设计师合作,他给了我一堆HTML文件……那么我就必须手动“翻译”它……通常情况下,大多数Web开发工具不会输出Hiccup结构,如果我正在使用Hiccup,处理HTML输出将是一件麻烦的事……这样我就可以把它放到“翻译器”中并获取所需的代码。 - zcaudate
@zcaudate 异端问题:为什么你不使用enlive呢? - kotarak
@kotarak 这是一个偏好和工作流程的问题...实际上,我发现当我调试东西时,我的大脑无法快速地在HTML和Clojure之间来回切换。把所有视图和模板都放在一个大文件中,方便剪切/粘贴/插入 - 而不是分开成HTML和代码两个部分。并且在Clojurescript中使用hiccup的等效物 - crate,这也很好用。 - zcaudate
4个回答

8
你可以从enlive中获取html资源以获得如下结构:

html-resource是指从enlive获取的一种结构:

{:tag :html :attrs {} :content []}

然后遍历它并将其转换为hiccup结构。
(defn html->hiccup
   [html]
   (if-not (string? html)
     (->> (map html->hiccup (:content html))
       (concat [(:tag html) (:attrs html)])
       (keep identity)
       vec)
     html))

以下是一个用法示例:

user=>  (html->hiccup {:tag     :p
                       :content ["Hello" {:tag     :a
                                          :attrs   {:href "/foo"}
                                          :content ["World"]}
                                 "!"]})
[:p "Hello" [:a {:href "/foo"} "World"] "!"]

谢谢!我之前尝试过查看enlive,但是因为它需要一个文件作为输入而感到困惑。在enlive中是否有任何方法可以输入字符串而不是资源? - zcaudate
1
我希望你可以定义一个简单的辅助函数:(defn str-resource [s] (html-resource (StringReader. s)))。未经测试。 - kotarak
现在有更好的答案,因为存在库; 请参见下面的链接:https://dev59.com/mmXWa4cB1Zd3GeqPJyGt#26006907 - Stuart Sierra

7

3

0

我写了一段代码片段,与Hickory不同的是,它可以真正跨平台运行,而不依赖于浏览器:

(ns hiccdown.html
  (:require [clojure.edn :as edn]
            [instaparse.core :as insta :refer [defparser]]))

(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)]))})))

更新:这段代码已成为Clojure库


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接