👊

XSLT Alternate Syntax(es)の一部

2020/12/03に公開

この記事はXSL Advent Calendar 2020の3日目の記事です。
https://adventar.org/calendars/5027

基本文法やる前にイロモノの話するのはよくないんですが。

Meta LanguageとかAlt-とか (2020-12-06修正)

<del>プログラミング関連で「メタ言語」というと、「ある言語で書かれた内容に変換される言語」といったところでしょうか。ちゃんと語ろうとすると例によってめっちゃ長くなるやつです。CSSに対してのSCSSとかは多分コレですね。</del>
<ins>2020-12-06追記 「メタ言語」といったとき、プログラミング言語の文脈ではOCamlなどML系のプログラミング言語が先に想起されるかもしれません。最もベーシックな意味としては「言語を表す言語」となるでしょう。XMLも「半構造記述言語」と呼ばれることもあり、ややこしくなるので、「ある言語で書かれた内容に変換される言語」として本記事では扱います。</ins>

Alt-JSというような言語があります。変換されてJavaScriptとして実行されるやつですね。観察範囲ではCoffeeScriptの話を見なくなりました。Overleafのリポジトリのコードくらい? TypeScriptもAlt-JSですね。トランスパイルされているうちはAlt-JSですが、ネイティブ実行されるとなるとAlt-JSとは呼べなくなってきますね。

メタ言語とAlt-のようなトランスパイルされる言語の違いについてはよく分かっていませんでしたが、大学時代からの先輩に「トランスパイルは手段である」と言われました。ある言語やパラダイム、指向で書きたいが、プラットフォームはトランスパイル先しか対応してないような。これもちゃんとした研究があるのかもしれない。

さて、日本語を表すのに仮名や漢字で書く方法、ローマ字で書く方法、発話する方法などがあるわけですが、これらは日本語という点では共通するワケです。ひだるまとしてはローマ字や仮名オンリーは書くのはともかく読み辛いので、仮名漢字アルファベット混合文で書くワケです。厳密にはそれぞれの表し方は等価では無いと思っていますが、同じ言語をを各々に馴染む方法で表現するわけですね。

本題です。XSLTは通常XMLで表されますが、XMLは勢いで書くには難しいです。それなりに一般に。リッチなIDEやGUIの補助があればまた違いますが、ターミナル越しにCLIでアクセスせざるを得ない状況なんてのもあるわけで。そこでメタXSLTの登場ですね。皆考えることは同じで、メタXSLTの試みは20年くらい前からあるみたいなので相当やぞ。そーいうワケでXSLTの別シンタックスを考える試みから幾つかピックアップして紹介します。

この前、社で「流行りは2000年代前半で今は下火~」みたいにこのトピックについて話したら「XSLメーリングリストでは今でも議論されてる」と御言葉を頂戴しました。XSLメーリングリスト入っていないことがバレてしまうね。そろそろ入ろうと思います。

Alt-JSなんかはJavaScriptが持っていない別機能を付けようとするものもあります。メタXSLTは方向性としては「とにかく短縮して書きたい」という傾向が強いように思います。観測範囲が偏っている可能性もありますが。短縮のパターンとしては概ね2つ、「インデント型」と「ブラケット型」です。XSLTというか、XMLのショートシンタックスを考える感じですね。それ以外にも設計思想は色々あるはずですが、variableがvariableじゃないこと、if-elseが無いこと(elseを表すのにchoose when otherwiseが必要なので労力が1.5倍くらいに感じる)を除けばXSLTはかなりよくできてるという了解があるのか、言語機能に手を入れてるのはあまり無い気がします。

以下、書いてある例はREADMEにあるものなどです。

XSLTScript

http://hg.nginx.org/xslscript

X:stylesheet {
X:template = "poem" {
 <html>
 <head>
 	<title> !{title} </title>
 </head>
 <body>
 	!! "title";
 	!! "author";
 	X:apply-templates "stanza";
 	X:apply-templates "date";
 </body>
 </html>
}
X:template = "title"  { <div align="center"><h1> !{.} </h1></div> }
X:template = "author" { <div align="center"><h2> By <% !{.} %> </h2></div> }
X:template = "stanza" { <p> !! "line"; </p> }
X:template = "line" {

X:if "position() mod 2 = 0" {&#160;&#160;} 
!{.} <br/>
}
X:template = "date" { <p><i> !{.} </i></p> }
}

これは偏見ですが、テンプレート言語っぽい見た目ですね。上の例はmatchだけだし見た目も素直なので対応するXSLTは載せません。

Rethinking XSLT

http://www.wilmott.ca/rxslt/rxslt.html

 template doc
   apply-templates
 template doc/title
   <H1>{apply-templates}</H1>
 template doc/para
   <P>{apply-templates}</P>
 <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:template match="doc">
     <xsl:apply-templates/>
   </xsl:template>
   <xsl:template match="doc/title">
     <H1><xsl:apply-templates/></H1>
   </xsl:template>
   <xsl:template match="doc/para">
     <P><xsl:apply-templates/></P>
   </xsl:template>
 </xsl:stylesheet>

Webサイト、結構前説明を割いている割に素直な記法です。インデントで省略するタイプ、複雑なネストが必要になってくると大変そうという感想を持ちました。

XLove

"Alternate syntax for XSLT" by David Love

# Strip all of the text out of an xml document
[ :xlt:("http://www.cs.rit.edu/˜dpl1926/xlt") ]
:xlt:main {
	:xlt:defun { :xlt:match { "*" }
		:xlt:lambda {
			:xlt:apply {
				:xlt:value { "node() | attribute::node()" } } } } }

下の変換はひだるまが書いているので間違っているかもしれない。

<xsl:template match="*">
	<xsl:apply-templates select="node() | attribute::node()" />
</xsl:template>

関数型言語っぽさが増しています。読み易いかどうかがかなり人による。元のXSLTより長くなる稀有な記法。

Carrot

https://github.com/evanlenz/Carrot

^(/) :=
  <html>
    <head>
      { /doc/title }
    </head>
    <body>
      { ^(/doc/para) }
    </body>
  </html>;
^(para) := <p>{^()}</p>;

^()xsl:apply-templates的になるのと、matchが式っぽい見た目になります。あと、これでxsl:copy-ofが走るって結構難しい気がする。XSLT 2.0になれるのがミソといえばミソ。

<xsl:transform version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="/">
    <html>
      <head>
        <xsl:copy-of select="/doc/title"/>
      </head>
      <body>
        <xsl:apply-templates select="/doc/para"/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="para">
    <p>
      <xsl:apply-templates/>
    </p>
  </xsl:template>

</xsl:transform>

SLAX

http://juniper.github.io/libslax/slax-manual.html

    match configuration {
        var $name-servers = name-servers/name;
        call my:thing();
        call my:thing($name-servers, $size = count($name-servers));
        call my:thing() {
            with $name-servers;
            with $size = count($name-servers);
        }
    }

    template my:thing($name-servers, $size = 0) {
        <output> "template called with size " _ $size;
    }
    <xsl:template match="configuration">
      <xsl:variable name="name-servers" select="name-servers/name"/>
      <xsl:call-template name="my:thing"/>
      <xsl:call-template name="my:thing">
        <xsl:with-param name="name-servers" select="$name-servers"/>
        <xsl:with-param name="size" select="count($name-servers)"/>
      </xsl:call-template>
      <xsl:call-template name="my:thing">
        <xsl:with-param name="name-servers" select="$name-servers"/>
        <xsl:with-param name="size" select="count($name-servers)"/>
      </xsl:call-template>
    </xsl:template>

    <xsl:template name="my:thing">
      <xsl:param name="name-servers"/>
      <xsl:param name="size" select="0"/>
      <output>
        <xsl:value-of
             select="concat('template called with size ', $size)"/>
      </output>
    </xsl:template>

実運用されてるためか、結構現実解っぽい記法です。とはいえ、要素の開始タグだけ書くやり方はSGMLっぽくて好きじゃないんだよな。XPathの方にもAlt記法があるんですが、新しいXPathでは同じような記法ができたりする。

Discussion