プログラミング言語XSLT

プログラミング言語XSLTの特徴

  • 関数型言語
  • チューリング完全
  • 引数はすべてキーワード引数
  • データ構造はすべて木構造(というかXML)
  • 入力データに起動するプログラムを記述する必要がある*1
  • C++のtemplateよりも遥かに冗長な構文
  • DSL(XPath)の力を借りないとほとんど何も出来ない中途半端さ


では早速、Hello, world!を表示するありきたりな例から。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version = "1.0">
  <xsl:template match="/">
    Hello, world!
  </xsl:template>
</xsl:stylesheet>


これだけでは何も出来ないので、呼び出し側を作る必要がありますね。
その前に、上のファイルをhello.xslとして保存しといてください。

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="hello.xsl"?>
<main/>

これを適当な名前(hello.xmlとか)で保存して、ブラウザで開けば画面にHello, world!と表示されるはずです。
プログラミング言語XSLTでは、このように最低2つのファイルが必要となるわけですね。
なんて回りくどい言語なんでしょうか。同じようにブラウザさえあれば実行できるJavaScriptと比べて、全然お手軽さが無いです。


ちなみにJavaScriptで同じようなことをやろうと思ったら、アドレスバーに

javascript:document.write("Hello, world!");

と入力してEnterを押すだけです。お手軽ですね。


しかしXSLTプログラマはこんな事ではくじけません。
XSLT関数型言語であることを示すために、foldl関数を実装して、それを使ってsum関数も実装してみましょう。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version = "1.0">

  <xsl:template name="foldl">
    <xsl:param name="func"/>
    <xsl:param name="init"/>
    <xsl:param name="list"/>
    
    <xsl:if test="$list">
      <xsl:variable name="result">
        <xsl:apply-templates select="$func[1]">
          <xsl:with-param name="arg0" select="$func[position() > 1]"/>
          <xsl:with-param name="arg1" select="$init"/>
          <xsl:with-param name="arg2" select="$list[1]"/>
        </xsl:apply-templates>
      </xsl:variable>
      <xsl:call-template name="foldl">
        <xsl:with-param name="func" select="$func"/>
        <xsl:with-param name="init" select="$result"/>
        <xsl:with-param name="list" select="$list[position() > 1]"/>
      </xsl:call-template>
    </xsl:if>
    <xsl:if test="not($list)">
      <xsl:copy-of select="$init"/>
    </xsl:if>
  </xsl:template>
  
  <xsl:template name="sum" xmlns:add="add">
    <xsl:param name="list"/>
    
    <xsl:variable name="adder" select="document('')/*/add:*[1]"/>
    <xsl:call-template name="foldl">
      <xsl:with-param name="func" select="$adder"/>
      <xsl:with-param name="list" select="$list"/>
      <xsl:with-param name="init" select="0"/>
    </xsl:call-template>
  </xsl:template>
  
  <xsl:template match="*[namespace-uri()='add']">
    <xsl:param name="arg1"/>
    <xsl:param name="arg2"/>
    
    <xsl:value-of select="$arg1 + $arg2"/>
  </xsl:template>
  
  <add:add xmlns:add="add"/>
  
  <xsl:template match="/">
    <xsl:call-template name="sum">
      <xsl:with-param name="list" select="/items/*"/>
    </xsl:call-template>
  </xsl:template>
</xsl:stylesheet>


・・・やはりこれだけでは何も出来ません。データを作る必要がありますね。
まずは上のファイルをtooverbose.xslとでも名前をつけて保存しておきましょう。
そして、以下の内容のファイルを適当な名前で作成してください。

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="tooverbose.xsl"?>
<items>
<item>10</item>
<item>5</item>
<item>2</item>
<item>3</item>
<item>11</item>
<item>6</item>
<item>5</item>
</items>

作ったXMLをブラウザで開くと結果が表示されるはず*2です。


さらに詳しいことはThe Functional Programming Language XSLT - A proof through examplesを読めば、あなたも明日からXSLTプログラマに!


一応、foldlとsumのJavaScriptによる実装例も置いておきますね。

function foldl(func, init, ary) {
    if (ary.length == 0) return init;
    return foldl(func, func(init, ary[0]), ary.slice(1, ary.length));
}

function sum(ary) {
    return foldl(function(a, b) { return a + b; }, 0, ary);
}

document.write(sum([10, 5, 2, 3, 11, 6, 5]));

・・・XSLTのすばらしさが際立ちますね!

*1:たぶん入力データそのものはXSLT側に持ってこれると思う。その場合は入力データに起動するプログラムを記述する必要はない

*2:面倒なのでIE7でしか試してない