list2html
HTMLパーサのところで、パース結果のlistをcl-whoに渡せば、HTML文字列が生成できるということを書いたが、整形されていなくても良いなら、変換処理自体はpretty-printを使って*1簡単に実装できる。
準備
参照: nlet
;; 型定義: car部がkeywordならHTMLリスト (defun html-element-p (obj) (and (consp obj) (keywordp (car obj)))) (deftype html-element () '(satisfies html-element-p)) ;; HTMLリスト操作関数群 (defun element-contents-position (elem) (nlet self ((rest (cdr elem)) (i 1)) (if (not (keywordp (car rest))) i (self (cddr rest) (+ i 2))))) (defun element-attributes (elem) (subseq elem 1 (element-contents-position elem))) (defun element-contents (elem) (subseq elem (element-contents-position elem)))
list -> HTML変換
(defvar *pprint-html* (copy-pprint-dispatch)) ;; 変換用テーブル登録 (set-pprint-dispatch 'html-element (lambda (stream elem &aux (name (car elem))) (if (eq name :!) ;; コメントと仮定(不正確) (format stream "<!-- ~A -->" (third elem)) ;; 通常の要素 (format stream "<~A~@[ ~{~A=~S~}~]~:[ /~;>~:*~{~A~}</~0@*~A~]>" name (element-attributes elem) (element-contents elem)))) 0 *pprint-html*) (defun list2html (html-lst) (with-output-to-string (*standard-output*) (write html-lst :pprint-dispatch *pprint-html*)))
実行
> (list2html '(:html (:head (:title "タイトル")) (:! :comment "コメント") (:body (:div :id 30 "テキスト1" (:br) "テキスト2")))) --> "<HTML><HEAD><TITLE>タイトル</TITLE></HEAD><!-- コメント --><BODY><DIV ID=30>テキスト1<BR />テキスト2</DIV></BODY></HTML>"
要素名等が全部大文字になってしまうが、(setf *print-case* :downcase)としておけば小文字に出来る。
*1:使わなくても、もちろん出来る