sxml の簡易シリアライズ

SXML (http://ja.wikipedia.org/wiki/SXML) の名前空間部分を無視して文字列化する、簡単なシリアライザーを gauche で書いた。
以下使用例。生成された文字列と、その前段階のリストを同時に返している。

gosh> (simple-sxml->xml '(tag))
"<tag/>"
("<" "tag" () "/>")
gosh> (simple-sxml->xml '(html (@ (lang "ja")) (body)))
"<html lang=\"ja\"><body/></html>"
("<" #0="html" ((" " "lang" "=\"" "ja" "\"")) ">" (("<body/>")) "</" #0# ">")
gosh> (simple-sxml->xml '(tag (@ (attr1 "v1") (attr2 "v2")) (nested "Text Node") (empty)))
"<tag attr1=\"v1\" attr2=\"v2\"><nested>Text Node</nested><empty/></tag>"
("<" #0="tag" ((#1=" " "attr1" #2="=\"" "v1" #3="\"") (#1# "attr2" #2# "v2" #3#)) ">" (("<nested>Text Node</nested>" "<empty/>")) "</" #0# ">")

パターンマッチには util.match を使う。string-append を使って文字列を逐次生成するのは冗長に感じられたので、一旦文字列のリストを生成した後、 text.tree で文字列にすることにした。

(use util.match)
(use text.tree)
(define (simple-sxml->xml x)
  (define (rep1 x attrs)
    `("<" ,(symbol->string x) ,attrs "/>"))
  (define (rep x attrs . body)
    (let1 s (symbol->string x)
      `("<" ,s ,attrs ">" ,body "</" ,s ">")))
  (define (iter tree)
    (match x
      ((tag) (rep1 tag '()))
      ((tag ('@ (attr value) ...))
       (rep1 tag
            (map (lambda (a v)
                   (list " " (symbol->string a) "=\"" v "\"")) attr value)))
      ((tag ('@ (attr value) ...) rest ...)
       (rep tag
            (map (lambda (a v)
                   (list " " (symbol->string a) "=\"" v "\"")) attr value)
            (map simple-sxml->xml rest)))
      ((tag rest ...)
       (rep tag '() (map simple-sxml->xml rest)))
      (() "")
      ((? string? s) s)))
  (let1 r (iter x)
    (values (tree->string r) r)))