木の変更
上にも書いた、木の更新のしかたが分からなくて驚いたという話。なんか基本的なことのような気がするんだけど……どうやればいいんだろう。
sxml で表現された HTML テンプレートをいじろうと思ったのですが、複雑な木の一部を変更する方法が分からなくて、結局関数にしてしまった。こんな感じ:
(define (template content) `(complex (@ (SXML TREE)) (DAYO) (hoge (@ (FUGA foo)) ,@content)))
これでは一般的じゃないので、例えば外部からテンプレートを読みこんで使おうなんていうときに困る。
(define (eval-template template params) ...)
こういう関数があって、
(define template-a '(complex (@ (SXML TREE)) (DAYO) (hoge (@ (%attrs)) (%content)))) (define params '((attrs (class "hoge")) (content (p "paragraph dayo") (div "div dayo"))))
こういうデータを
(srl:sxml->xml (eval-template template-a params))
なんていうふうにできると嬉しいと思う。
tree の更新なんて fold がハマるパターンだよねーと思って、書いた。
(define (templatesymbol? symbol) (and (symbol? symbol) (eq? (string-ref (symbol->string symbol) 0) #\%))) (define (eval-template template params) (fold-right (lambda (x list) (if (not (pair? x)) (cons x list) (or (and-let* (((templatesymbol? (car x))) (content (assoc-ref params (car x)))) (append content list)) (cons (eval-template x params) list)))) () template))
(define template '(*TOP* (html (@ (xmlns "http://www.w3.org/1999/xhtml") (lang "ja")) (head (title "html template test")) (body (h1 "tempalate test") (%content))))) (pretty-print (eval-template template '((%content (p (@ (class "content")) "hogefugafoobar") (p (@ (class "content")) "hogefugafoobar"))))) ;=> (*TOP* (html (@ (xmlns "http://www.w3.org/1999/xhtml") (lang "ja")) (head (title "html template test")) (body (h1 "tempalate test") (p (@ (class "content")) "hogefugafoobar") (p (@ (class "content")) "hogefugafoobar"))))
実行効率とかはどうなんだろう。コンシングが多いんじゃないか?と思ったけど、テンプレートをメモリ上に保持するならコピーは避けられないわけで、問題無い。