包裹html标签围绕着贴印的clojure表格

发布于 2025-01-25 06:10:48 字数 761 浏览 4 评论 0 原文

Clojure的漂亮打印机(clojure.pprint)采用了这样的未构造代码:

(defn fib ([n] (fib n 1 0)) ([n a b] (if (= n 0) a (fib (dec n) (+ a b) a))))

并使其变得不错。

(defn fib
  ([n] (fib n 1 0))
  ([n a b]
   (if (= n 0)
       a
       (fib (dec n) (+ a b) a))))

我想在网页中放一些来源,所以我希望它是相当印刷的。但是我也想将每种形式包裹在一组&let中;跨度>具有唯一ID的标签,因此我可以用JavaScript操纵表示形式。也就是说,我想变成

(foo bar baz)

<span id="001">(<span id="002">foo</span> <span id="003">bar</span> <span id="004">baz</span>)</span>

但我仍然希望所产生的表格像漂亮的打印机一样被缩进,以便实际显示的代码看起来正确。

精美打印机的一些文档提到它可以采用自定义调度函数,但我找不到有关它们所做的事情或如何定义它们的任何内容。是否可以用这样的野兽来做我想做的事,如果有人可以为我提供有关如何做的信息?

Clojure's pretty printer (clojure.pprint) takes unformatted code like this:

(defn fib ([n] (fib n 1 0)) ([n a b] (if (= n 0) a (fib (dec n) (+ a b) a))))

And makes it nice, like this.

(defn fib
  ([n] (fib n 1 0))
  ([n a b]
   (if (= n 0)
       a
       (fib (dec n) (+ a b) a))))

I'd like to put some source in a web page, so I'd like it to be pretty-printed. But I'd also like to wrap each form in a set of < span > tags with a unique ID so I can manipulate the representation with javascript. That is, I want to turn

(foo bar baz)

into

<span id="001">(<span id="002">foo</span> <span id="003">bar</span> <span id="004">baz</span>)</span>

But I still want the resulting forms to be indented like the pretty printer would, so that the code that actually gets displayed looks right.

Some of the documentation for the pretty printer mentions that it can take custom dispatch functions, but I can't find anything about what they do or how to define them. Is it possible to do what I want with such a beast, and if so can someone provide me with some information on how to do it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

━╋う一瞬間旳綻放 2025-02-01 06:10:48

您可以在此处看到,有多种方法可以打印XML:

该人使用的

(defn ppxml [xml]
  (let [in (javax.xml.transform.stream.StreamSource.
            (java.io.StringReader. xml))
        writer (java.io.StringWriter.)
        out (javax.xml.transform.stream.StreamResult. writer)
        transformer (.newTransformer 
                     (javax.xml.transform.TransformerFactory/newInstance))]
    (.setOutputProperty transformer 
                        javax.xml.transform.OutputKeys/INDENT "yes")
    (.setOutputProperty transformer 
                        "{http://xml.apache.org/xslt}indent-amount" "2")
    (.setOutputProperty transformer 
                        javax.xml.transform.OutputKeys/METHOD "xml")
    (.transform transformer in out)
    (-> out .getWriter .toString)))

是,如果将html字符串放置(这不是XML的子集),您将获得:

(ppxml "<root><child>aaa</child><child/></root>")

输出:输出:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <child>aaa</child>
  <child/>
</root>

在Clojure,使用Compojure,您可以在非常lis的语法中构建HTML/XML标签。
您也可以使用它们:

(ppxml (html
        [:html
         [:head
          [:title "Hello World"]]
         [:body "Hello World!"]]))

输出的输出:

<html> 
  <head> 
    <title>Hello World</title> 
  </head> 
  <body>Hello World!</body> 
</html>

您在此处看到建议:
compojure html格式

There are ways to pretty print XML, as you can see here:
https://nakkaya.com/2010/03/27/pretty-printing-xml-with-clojure/

That person used

(defn ppxml [xml]
  (let [in (javax.xml.transform.stream.StreamSource.
            (java.io.StringReader. xml))
        writer (java.io.StringWriter.)
        out (javax.xml.transform.stream.StreamResult. writer)
        transformer (.newTransformer 
                     (javax.xml.transform.TransformerFactory/newInstance))]
    (.setOutputProperty transformer 
                        javax.xml.transform.OutputKeys/INDENT "yes")
    (.setOutputProperty transformer 
                        "{http://xml.apache.org/xslt}indent-amount" "2")
    (.setOutputProperty transformer 
                        javax.xml.transform.OutputKeys/METHOD "xml")
    (.transform transformer in out)
    (-> out .getWriter .toString)))

So if you put your HTMl string (which is not exactly a subset of XML), you would get:

(ppxml "<root><child>aaa</child><child/></root>")

output:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <child>aaa</child>
  <child/>
</root>

In Clojure, using Compojure, you can build HTML/XML tags in a very lispy syntax.
You can use them too:

(ppxml (html
        [:html
         [:head
          [:title "Hello World"]]
         [:body "Hello World!"]]))

With the output of:

<html> 
  <head> 
    <title>Hello World</title> 
  </head> 
  <body>Hello World!</body> 
</html>

You see also suggestions here:
Compojure HTML Formatting

春庭雪 2025-02-01 06:10:48

这是可能的,但我认为这比您预期的要多得多。您将使用源代码并修改已经存在的功能。

您肯定需要 with-ppprint-dispatch 。此函数使用给定的调度函数执行主体:

(with-pprint-dispatch code-dispatch
                      (pprint '(foo bar baz)))
(foo bar baz)
=> nil

寻找函数 code code-dispatch ,并查看其定义:

(defmulti 
  code-dispatch
  "The pretty print dispatch function for pretty printing Clojure code."
  {:added "1.2" :arglists '[[object]]} 
  class)

(use-method code-dispatch clojure.lang.ISeq pprint-code-list)
(use-method code-dispatch clojure.lang.Symbol pprint-code-symbol)

;; The following are all exact copies of simple-dispatch
(use-method code-dispatch clojure.lang.IPersistentVector pprint-vector)
(use-method code-dispatch clojure.lang.IPersistentMap pprint-map)
(use-method code-dispatch clojure.lang.IPersistentSet pprint-set)
(use-method code-dispatch clojure.lang.PersistentQueue pprint-pqueue)
(use-method code-dispatch clojure.lang.IDeref pprint-ideref)
(use-method code-dispatch nil pr)
(use-method code-dispatch :default pprint-simple-default)

如您所见,每个集合类型都有特殊的功能。我刚刚选择了列表和矢量,我的调度函数看起来像这样:

(defmulti
  my-code-dispatch
  class)

(use-method my-code-dispatch clojure.lang.ISeq my-pprint-code-list)
(use-method my-code-dispatch clojure.lang.IPersistentVector my-pprint-vector)
(use-method my-code-dispatch :default my-pprint-simple-default)

现在,寻找 pprint-code-list pprint-vector pprint-simple-default 。其中两个使用 pprint-logical-block 使用关键字:前缀:后缀 - 在这里您插入其他字符串(其余函数将相同)。不要忘记为跨度编号定义一些计数器:

(in-ns 'clojure.pprint)

(def id (atom 0))

(defn- my-pprint-vector [avec]
  (pprint-meta avec)
  (pprint-logical-block :prefix (format "<span id=\"%03d\">[" (swap! id inc))
                        :suffix "]</span>"
...)

(defn- my-pprint-simple-default [obj]
  (cond
    (.isArray (class obj)) (pprint-array obj)
    (and *print-suppress-namespaces* (symbol? obj)) (print (name obj))
    :else (cl-format true "<span id=\"~3,'0d\">~s</span>"
                       (swap! id inc)
                       obj)))

(defn- my-pprint-simple-code-list [alis]
  (pprint-logical-block :prefix (format "<span id=\"%03d\">(" (swap! id inc))
                        :suffix ")</span>"
...)

(defn- my-pprint-code-list [alis]
  (if-not (pprint-reader-macro alis)
    (if-let [special-form (*code-table* (first alis))]
      (special-form alis)
      (my-pprint-simple-code-list alis))))

使用所有这些设置,我打电话给:

(with-pprint-dispatch my-code-dispatch
                      (pprint '(foo bar baz)))

<span id="001">(<span id="002">foo</span>
                 <span id="003">bar</span>
                 <span id="004">baz</span>)</span>
=> nil

或者您可以将其打印到字符串中:

(with-out-str (with-pprint-dispatch my-code-dispatch
                                    (pprint '(foo bar baz))))
=>
"<span id=\"001\">(<span id=\"002\">foo</span>\r
                  <span id=\"003\">bar</span>\r
                  <span id=\"004\">baz</span>)</span>\r
 "

我必须再次提及,要打印一些真实的代码,您必须修改所有功能数据类型。如此 - 有可能吗?是的。值得努力吗?我怀疑。

It's possible, but I think it's much more work than you expect. You'll work with source code pprint/dispatch and modify functions that are already here.

You'll surely need with-pprint-dispatch. This function uses given dispatch function to execute body:

(with-pprint-dispatch code-dispatch
                      (pprint '(foo bar baz)))
(foo bar baz)
=> nil

Look for function code-dispatch and see it's definition:

(defmulti 
  code-dispatch
  "The pretty print dispatch function for pretty printing Clojure code."
  {:added "1.2" :arglists '[[object]]} 
  class)

(use-method code-dispatch clojure.lang.ISeq pprint-code-list)
(use-method code-dispatch clojure.lang.Symbol pprint-code-symbol)

;; The following are all exact copies of simple-dispatch
(use-method code-dispatch clojure.lang.IPersistentVector pprint-vector)
(use-method code-dispatch clojure.lang.IPersistentMap pprint-map)
(use-method code-dispatch clojure.lang.IPersistentSet pprint-set)
(use-method code-dispatch clojure.lang.PersistentQueue pprint-pqueue)
(use-method code-dispatch clojure.lang.IDeref pprint-ideref)
(use-method code-dispatch nil pr)
(use-method code-dispatch :default pprint-simple-default)

As you can see, there is special function for each collection type. I just picked list and vector and my dispatch function looks like this:

(defmulti
  my-code-dispatch
  class)

(use-method my-code-dispatch clojure.lang.ISeq my-pprint-code-list)
(use-method my-code-dispatch clojure.lang.IPersistentVector my-pprint-vector)
(use-method my-code-dispatch :default my-pprint-simple-default)

Now, look for pprint-code-list, pprint-vector and pprint-simple-default. Two of them use pprint-logical-block with keywords :prefix and :suffix- that's the place where you insert additional string (the rest of function will be the same). Don't forget to define some counter for span numbering:

(in-ns 'clojure.pprint)

(def id (atom 0))

(defn- my-pprint-vector [avec]
  (pprint-meta avec)
  (pprint-logical-block :prefix (format "<span id=\"%03d\">[" (swap! id inc))
                        :suffix "]</span>"
...)

(defn- my-pprint-simple-default [obj]
  (cond
    (.isArray (class obj)) (pprint-array obj)
    (and *print-suppress-namespaces* (symbol? obj)) (print (name obj))
    :else (cl-format true "<span id=\"~3,'0d\">~s</span>"
                       (swap! id inc)
                       obj)))

(defn- my-pprint-simple-code-list [alis]
  (pprint-logical-block :prefix (format "<span id=\"%03d\">(" (swap! id inc))
                        :suffix ")</span>"
...)

(defn- my-pprint-code-list [alis]
  (if-not (pprint-reader-macro alis)
    (if-let [special-form (*code-table* (first alis))]
      (special-form alis)
      (my-pprint-simple-code-list alis))))

With all this setup, I called:

(with-pprint-dispatch my-code-dispatch
                      (pprint '(foo bar baz)))

<span id="001">(<span id="002">foo</span>
                 <span id="003">bar</span>
                 <span id="004">baz</span>)</span>
=> nil

Or you can print it into string:

(with-out-str (with-pprint-dispatch my-code-dispatch
                                    (pprint '(foo bar baz))))
=>
"<span id=\"001\">(<span id=\"002\">foo</span>\r
                  <span id=\"003\">bar</span>\r
                  <span id=\"004\">baz</span>)</span>\r
 "

And I have to mention again that for printing some real code, you would have to modify all functions for all data types. So- it's possible? Yes. Worth the effort? I doubt it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文