CL-WHO 基于生成 write 语句的宏,所有以关键字开头的表单以及参数值都会自动打印。其他形式仅被评估(例如,用于副作用),并且不会自动打印。这就是 CL-WHO 引入str
、和macrolets 的原因fmt
,它们会强制打印它们的参数(以不同的方式)。esc
htm
你的代码:
(defun bar ()
(with-html-output-to-string
(*standard-output* nil :prologue t)
(htm "This will NOT show up in the html stream")))
返回值是一个字符串,因为您使用的是with-html-output-to-string
. *standard-output*
临时绑定到一个流,与外面的不同,bar
只是为了构建一个返回给调用者的字符串,here foo
。不打印字符串(仅打印内容位置为常量字符串的表单)。
您可以使用 强制写入返回的生成 HTML str
,但恕我直言,最好的选择是直接写入与调用者相同的输出流,而不是构建中间字符串。
直接写入流
基本上,使用with-html-output
:
下面定义一个包并配置 CL-WHO 以发出 HTML5 代码。这必须在宏扩展之前完成,因为在宏扩展期间使用了正在设置的特殊变量:
(defpackage :web (:use :cl :cl-who))
(in-package :web)
;; Evaluate before CL-WHO macro are expanded
(eval-when (:compile-toplevel :load-toplevel :execute)
(setf (html-mode) :html5))
定义一个我们可以控制的流,默认*standard-output*
绑定到我们打开流时绑定的任何内容(而不是在我们定义变量时):
(defvar *html-output* (make-synonym-stream '*standard-output*)
"Use a dedicated stream variable for html")
另外,定义一个通用的缩进级别:
(defvar *indent* 2
"Default indentation")
有两个宏,一个用于嵌入在辅助函数中的片段,它写入我们的流中,另一个用于顶级 html 页面,它返回一个字符串。
(defmacro with-html (&body body)
"Establish an HTML context (intended for auxiliary functions)."
`(with-html-output (*html-output* nil :indent *indent*)
,@body))
(defmacro with-html-page (&body body)
"Return an HTML string (intended for top-level pages)."
`(with-html-output-to-string (*html-output* nil :prologue t :indent *indent*)
,@body))
示例用法:
(defun my-section (title)
(with-html
(:h1 (esc title))
(:p "lorem ipsum")))
(defun my-page ()
(with-html-page
(my-section "title")))
调用(my-page)
返回:
"<!DOCTYPE html>
<h1>title
</h1>
<p>lorem ipsum
</p>"
另见鲜为人知的https://github.com/ruricolist/spinneret。