ボルボックス


ムダなくすばやくすべてを
volvox

パイプラインとは

概要

2012.09.01

ツール”ボルボックス”は、XMLパイプライン・モデルを解釈する、かんたんな解釈器(インタプリタ)です[※1]。

概念:パイプライン

2012.09.01

パイプラインはUNIXに実装された、プログラムの入力/出力をつなぐしくみです[※1]:

PROGRAM1 | PROGRAM2 | PROGRAM3 | ...
※1
ここでPROGRAM1 の出力はPROGRAM2 の入力になります。単純なプログラムの連結により、パイプに流れるストリーム(文字列)を複雑に変換することができます。

概念:XMLパイプライン

2012.09.01

UNIXのパイプライン・モデルをXML形式で表したものが、XMLパイプラインです[※1][※2][※3]。

ただしパイプの始端と終端は、中間(中間エントリ)から区別されます。始端エントリはパイプに対し出力のみを行い、終端エントリはパイプからの入力のみを扱います[※4]:

<... xmlns:vox="http://common.xoxxox.net/docmgr">
<vox:map>    .... パイプライン
  <vox:xml>  .... 始端エントリ(パイプラインの始端……XMLなど)
  <vox:xsl>  .... 中間エントリ(パイプラインの中間……XSLなど)
  <vox:gen>  .... 終端エントリ(パイプラインの終端)

それぞれのエントリには、次の基本関数が使えます:

exe:FUNCTION .... プログラムの呼び出し(拡張関数)
sys:EXEFILES .... プログラムの呼び出し(コマンド)
var:ARGUMENT .... 変数への書き込み
val:AAGUMENT .... 変数から読み出し
gen:         .... パイプライン処理
end:         .... 強制終了
※1
簡易なドメイン固有言語(DSL)の一種ですが、制御構造は順序構造のみで、条件分岐/繰り返しはありません(制御以外には、変数、外部ルーチン/コマンドの呼び出し、XML文書の結合/分配、があるだけです)……これは(XSLTなどの)チューリング完全な言語からコードそのものを生成し、そのコードをストリームとして実行することを想定しているからです。
※2
このツールで利用者は、通常のパイプライン、および擬似的パイプラインの2つのデータ受け渡し方法を選ぶことができます。通常のパイプラインはプロセス間のストリーム・データの受け渡しを提供し、基本関数には”sys:”を使います。疑似的パイプラインはプロセス内における文字列変数か一時ファイルによるデータの受け渡しを提供し、基本関数には”exe:”を使います(つまり本来のパイプではなく、書式を合わせるためのみせかけのパイプにすぎません)。いずれの「パイプ」でも交換されるのは無構造の文字列であり、XML形式であるかどうかは問いません。ただし複数の始端エントリがある場合はそれらを結合するので、結合方法の指定によっては内容がXML形式であることが求められます。
※3
パイプラインをXML形式で表すのは、これをXSL(XSLT)であつかうことを前提としているからです……とはいえいまのところ、アプリケーション開発でパイプラインを多段のXSLで処理する場面に遭遇したことはなく(生成はするが入力にはならない)、XML形式の利点は、そのシンタックス判定をXSLインタプリタに任せられるという部分にのみとどまっています(なおパイプラインを他の言語であつかう場合は、XML形式である必然性もありません)。
※4
始端エントリも終端エントリも複数記述できます。複数の始端エントリは、それぞれの内容を結合して中間エントリに出力します。複数の終端エントリは、入力された内容を分配してそれぞれが独自に動作します。もちろん中間エントリも複数記述でき、ここでは前のエントリの出力が次のエントリの入力となります。

例示:XMLパイプライン

2012.09.01

たとえば、XMLファイルにXSLファイルを適用しHTMLファイルを生成するパイプラインは(単純な静的CMS)[※1]:

<vox:map>
  <vox:xml>get:sample.xml</vox:xml>
  <vox:xsl>use:sample.xsl</vox:xsl>
  <vox:gen>set:sample.htm</vox:gen>
</vox:map>

ファイルに出力するのでなく、ウェブブラウザの画面に出すなら(単純な動的CMS〜PHP風の動作):

<vox:map>
  <vox:xml>get:sample.xml</vox:xml>
  <vox:xsl>use:sample.xsl</vox:xsl>
  <vox:gen>web:</vox:gen>
</vox:map>

ブラウザのフォーム入力(HTTPクエリ)内容をメールで送るなら(単純なメールフォーム・プログラム):

<vox:map>
  <vox:xml>req:</vox:xml>
  <vox:xsl>use:sample.xsl</vox:xsl>
  <vox:gen>msg:</vox:gen>
</vox:map>

ほかにもRDBとの連携やRDFクエリ、日時出力などの拡張関数を用意しており、さまざまな応用が可能です。

XMLパイプラインは無構造の文字列をあつかうので、UNIXのパイプラインを模すこともできます:

<vox:map>
  <vox:xml>sys:cat sample.txt</vox:xml>
  <vox:xsl>sys:grep 'sample'</vox:xsl>
  <vox:xsl>sys:sed '/sample/SAMPLE/g'</vox:xsl>
  <vox:xsl>sys:sort</vox:xsl>
  <vox:gen>out:</vox:gen>
</vox:map>

このように文書の処理には、標準のXSL(XSLT)だけでなく、さまざまなフィルタ(sed/awk/grep/...)やインタプリタが使えます(perl/ruby/python/scheme/haskell/... )。複数のフィルタ様式やプログラム言語を扱えるため、複雑な問題にも対応できる仕様となっています[※2]。

※2
じっさい”ボルボックス”はXSL(XSLT)の解釈器ですらないので(XSLインタプリタは周辺ドライバ(拡張関数)のひとつです)、利用者が望むなら、文書処理にはあらゆるスタイル・シートの処理器を選択できます(ウィキ風の軽量マークアップ言語から〜各種CMSの専用スタイル言語のインタプリタ、さらには標準とはべつのXSL解釈器まで)……それらのドライバに求められるのは、標準入力〜標準出力の機能をもつことのみです。
※1
ここではコードを読みやすくするため、いくつかの拡張関数に読み替え規則を適用しています(これらの規則は、構成ファイルの組み込みテンプレートのひとつとして提供されます):
get:FILE -> exe:Xexstd::getfil 'FILE' ... ファイルの読み込み
use:FILE -> exe:Xexstd::usefil 'FILE' ... ファイルの読み込み〜XSL適用
set:FILE -> exe:Xexstd::setfil 'FILE' ... ファイルの書き出し
out: -> exe:Xexstd::outmon ... OS標準出力への出力
req: -> exe:Xexweb::getmon 'g' ... ウェブのHTTPリクエストからの入力
web: -> exe:Xexweb::outmon 'h' ... ウェブのブラウザへの出力
msg: -> exe:Xexmsg::sndmsg ... メールの送信

概念:パイプラインの生成

2012.09.01

XMLパイプラインそのものを適切に生成することで、さまざまなアプリケーションを作成できます。

XMLパイプラインには、終端エントリへの入力を再びパイプライン解釈器に渡す、基本関数を組み込んでいます(”gen:”関数)。

XMLパイプラインはそれ自体がXML形式の文書なので、パイプラインを通して、XMLパイプラインの記述そのものを生成することができます。パイプラインに入力される内容に応じて適切なパイプラインを生成することで、入力に応じて出力を変える、ひとつのプロセスを作ることができます。このようなプロセスを生むモジュールを適切に組み合わせることで、いわゆるアプリケーションを作成できます[※1][※2][※3][※4][※5]。

※1
つまり各種ウェブ・アプリケーションを、単純なタグのブロック(XMLパイプライン)を組み合わせることで作成できる、ということです。これはIIDツールのひとつです。
※2
パイプラインの生成は、メタプログラミングに似ています。ただしパイプラインには条件分岐/繰り返しがなく、生成されたコードには順序構造しかありません。そもそもパイプラインを生成するコードの解釈器と、パイプラインを解釈する解釈器は違います。その意味でこれは、「メタパイピング」というべきものです……メタプログラミングは自由度が高い反面、危険で可読性の低いコードを生みがちですが、単純なコードを生成するメタパイピングは、そのようなデメリットを回避しています。
※3
ここで”プロセス”は、XMLパイプライン解釈器が一度呼ばれ〜解釈器への再投入がすべてなくなるまで(=最終的なXMLパイプライン文書が生成されるまで)の処理単位をいいます。
※4
最終的に生成されるXMLパイプラインのセットは、プログラムの設計によっては大きなサイズになることがあります。サイズが大きくなり(機器のメモリが圧迫されるなどの)弊害が予測されるときは、設計の段階から擬似的パイプラインの使用を避けることを勧めます。
※5
パイプライン処理を特定のプログラミング言語の拡張機能(たとえばXSLの拡張関数)として組み込む、という方法もあります。いまのところ”ボルボックス”は言語独立(あるいは言語に独自機能を追加しない)の方針にしたがい、特定の言語に依存するような実装は行いません。

例示:パイプラインの生成

2012.09.01

XSL(XSLT)はスタイル・シートであるとともに、チューリング完全なプログラミング言語のひとつです。このような言語を使うことで、入力に応じた適切なXMLパイプライン文書(=入力〜出力のフロー)を生成できます[※1][※2][※3]:

たとえばプログラムの記述は次のようになります(ここではウェブから得たクエリ文字列で、プロセスの挙動を決めています。最初の中間エントリで読み込まれるものは、XMLパイプラインそのものを生成するXSLファイルです):

<vox:map>
  <vox:xml>req:</vox:xml>
  <vox:xsl>use:xpipes.xsl</vox:xsl>
  <vox:gen>gen:</vox:gen>
</vox:map>
xpipes.xsl
<xsl:variable name="queryx"><xsl:value-of select="/*/queryx"/></xsl:variable>
<xsl:variable name="queryy"><xsl:value-of select="/*/queryy"/></xsl:variable>
...
<xsl:if test="$queryx ...">
  <vox:map>
  <vox:xml>...</vox:xml>
  <vox:xsl>...</vox:xsl>
  <vox:gen>...</vox:gen>
  </vox:map>
</xsl:if>
...
<xsl:call-template name="...">
<xsl:with-param name="argumx"><xsl:value-of select="$queryx"/></xsl:with-param>
<xsl:with-param name="argumy"><xsl:value-of select="$queryy"/></xsl:with-param>
</xsl:call-template>
...
<xsl:template name="...">
<xsl:param name="argumx"/>
<xsl:param name="argumy"/>
  <vox:map>
  <vox:xml>...<xsl:value-of select="$argumx"/>...<xsl:value-of select="$argumy"/>...</vox:xml>
  <vox:xsl>...</vox:xsl>
  <vox:gen>...</vox:gen>
  </vox:map>
</xsl:template>
※1
これは実装面からみれば、アプリケーションのメインの処理もXSLTで書くことができる、ということです。このときXSLTは、XMLパイプライン記述を生成するためのスタイルシートです。またXMLパイプラインは文書変換のための中間コードであり、中間コードのインタプリタは任意のプログラミング言語で実装されます。そしてそれはメインの処理からはみえません……つまり、アプリケーションのフロントエンドだけでなくメインの処理もW3C標準の言語(XSLT)で記述でき、そのコードは(W3C標準以外の)特定のプログラミング言語に依存しない、ということです。
※2
パイプラインの生成にXSLTを推奨するのは、それが(文書設計の標準でありプログラム間の入力〜出力にも使われる)XML形式のデータを簡潔にあつかえるからです(たしかにXSLTプログラムの記述量は大きくなりがちですが、抽象的にみれば、その関数型のコードはとてもコンパクトです)。またXSLTを知っているなら(XSLTは標準のスタイルシート記述言語です)、パイプライン生成のために他の言語を知る必要がありません。さらにXSLTはチューリング完全でありながら、入出力を備えていない軽量な言語のひとつです。そのXSLTに入出力機能をつけるソリューションのひとつがXMLパイプラインなので、多様な入出力を備えている言語では、機能が重複してしまいます。
※3
とはいえ”ボルボックス”はパイプラインの解釈器でしかなく、入力が仕様に則ったXML形式パイプライン(vox:map )であることのみを要求します。それを生成する処理器は任意なので、利用者が望むなら、パイプラインの生成(プログラミング)にもあらゆる言語(perl/ruby/python/scheme/haskell/... )を使えます。