golden-luckyの日記

ツイッターより長くなるやつ

XMLをLisp評価器で実行する

昨日は、ドキュメントとは木であり、その木はXML、さらにいうとXMLアプリケーションとして形作られる、という話をしました。 一般にドキュメントは、生のままの構造として読み手に与えられるものではありません。 ドキュメントの構造が何らかのXMLアプリケーションであれば、本来はそのスキーマに従って解釈し、しかるべきスタイルを適用することになります。

ここで、しばしば厄介になるのは、XMLアプリケーションのスキーマを正しく扱うのはなかなか大変だということです。 そもそも、プロプラなXMLアプリケーションだと、スキーマの定義が手に入らない場合もあります。 そういった「野良XMLをどうやって扱うか」が今日からの話題です。

でもその前に、昨日の記事の最後で紹介したSXMLについて雑に補足しておきます。

XMLをSXMLに引き写すことで見える景色

さて、昨日はSXMLという技術を紹介しました。 SXMLのSはS式のSです。 簡単に言うと、こういうXMLで構造が表されている書籍は…、

<book>
  <info>
    <author>著者</author>
    <title>本タイトル</title>
  </info>
  <chapter>
    <title>章タイトル</title>
    <para>段落の本文</para>
  </chapter>
</book>

こういうS式で表せます。

(book
  (info
    (author "著者")
    (title "本タイトル"))
  (chapter
    (title "章タイトル")
    (para "段落の本文" (b "ここは太字") )))

ところで、みなさんご存じのように、S式はLispというプログラミング言語で(現代では)主に採用されています。 Lispというプログラミング言語におけるS式は、Lispシンタックスであると同時に、抽象構文木でもあります。 Lispでは、S式で表された抽象構文木をそのまま評価器で実行でき、しかもマクロでDSLを作れます。

さて、ここで、一昨日の記事を思い出してください。 そこでは、「ドキュメントの構造はプログラミング言語における抽象構文木に対応している」と述べました。 そしてSXMLでは、ドキュメントの構造がS式で表現されています。

ということは、ドキュメントの構造をそのままLispで実行できそうに思えませんか?

XMLをわざわざS式で表現することには、見た目の雰囲気を変えただけでなく、「ドキュメントの構造をプログラミング言語の抽象構文木と同じように評価できる」ことを思い出させてくれる効能があったのです(ただしLispプログラマーにとって)。 スキーマ言語XMLアプリケーションを作るのと事実上同じことが、SXMLであればLispのマクロとして、より直観的に実現できると言ってもいいでしょう。

SXMLをLispで「評価」する

野良XMLLispマクロで手なずける前に、「LispでSXMLを評価する」ことについて、Lispを少ししか知らない人向けに補足しておきます。

先ほど例として示した書籍の構造を表すSXMLの一部には、次のようなS式が含まれていました。

(para "段落の本文")

このSXMLは「paraという関数に引数を適用する」と見なせます。 この場合の引数は"段落の本文"という文字列です。

山かっこのXMLだと「段落要素を表す<para>タグ」にしか見えなかったものが、SXMLだと関数適用に見えるのがわかるでしょうか。 たとえば、(para ...)というSXMLをLaTeXの段落として出力したければ、関数paraを「引数の中身をLaTeXの段落として出力する」というふうに定義すればよいでしょう。

(define (para arg)
  (print arg "\n\n"))

同様に、関数bを「引数の中身をLaTeXの太字として出力する」というふうに定義すれば、(b ...)というSXMLの項を評価した結果はLaTeXの太字になります。

(define (b arg)
  (print "\\textbf{" arg "}"))

こんな感じで元のXMLに出現するタグと同じ名前の関数にしかるべき定義を与えてあげれば、あとはSXMLの全体をLispの評価器で実行するだけで、「元のXMLアプリケーションを処理した結果」が得られるという寸法です。 画期的ですね。

(define (book arg)
  ("\\documentclass{jsbook}\n\\begin{document}" arg "\\end{document}"))

ただ、これだけだと、argの中身が再帰的に評価されないのでうまくいきません。 そのへん、もうちょっとちゃんと定義してあげる必要があります。

また、XML名前空間や属性の扱いなども、それなりに対処してあげる必要があります。 SXMLでこれらを扱うのは、XMLスキーマを書くときと同様に、わりと大変です。 そもそも、素性のわからない野良XMLの中身を見ながら「元のXMLに出現するタグと同じ名前の関数にしかるべき定義を与えてあげる」という作業はかなりうっとうしい。

SXMLを評価することで野良XMLに意味を与える、というアイデアを実用的なものにするには、これらの細かい部分を抽象化してくれるフレームワークが欲しくなります。

明日は、そういうフレームワークを実装する話をします。