小ネタ:テンプレート言語でできてXSLTでできないこと(修正)
2020-12-05 escape処理について追記
2020-12-06 character-mapによる置換について追記
この記事はXSL Advent Calendar 2020の4日目の記事です。
ネタがないのではなく、ネタが重くて書き終わらない。
小ネタです。Zennのスクラップ機能、調べてないから分からないけどそっちの方がいいのかな。
forがないとかif-elseがないというのは瑣末で、似たようなことはできるわけです。
さて、XSLTは整形式のXMLである必要があります。形式が整っているということはつまり、「互い違いの要素は許容されない」ということです。暫く触っていれば当たり前体操なんですが、ひだるまは最初の頃そこそこはまりました。
一般的なテンプレート言語で書かれがちな条件分岐として、こんなものがあります。
{{ if context }}
<div style="hoge">
{{ endif }}
{{ else }}
<div style="fuga">
{{ endif }}
</div>
これをXSLTにそのまま移そうとした次のコードは不正です。
<!-- 不正 -->
<xsl:choose>
<xsl:when test="context">
<div style="hoge">
</xsl:when>
<xsl:otherwise>
<div style="fuga">
</xsl:otherwise>
</xsl:choose>
</div>
if(when)の中で<div>
が始まったのに、その終了</div>
が幾つか入れ子を飛び越えていますね。壊れたHTMLタグはWebブラウザが頑張って表示してしまいますが、XSLT処理系はこれでは多分動きません。
出力形式がXMLでないことにすれば多分少し無茶もできますが、不利益の方が多分勝ります。
追記箇所:
指摘頂きました通り、@disable-escape-escaping="true"
や<![CDATA]>
を用いてoutput method="xml"のままでも処理できますね。規約違反かと言われるとそうでもないです。「XSLTでできないこと」を記事タイトルにするのはよくありませんでしたね。
XMLであることを一部とはいえ放棄するので、TypeScriptだとany
を使うような話程度ですかね。つまり、人や状況によって許されたり許されなかったりする。
追記箇所:コメントでいただきましたように、文字を別のタイミングで置き換えるcharacter-mapの処理を行うことでも回避は可能ですね。
XSLTで回避すべきなのはこの条件分岐の書き方そのものという意図があったりしたんですが、タイトルからして「可能不可能」にフォーカスしたものになってるのしこれは私の記事の書き方が下手。
おまけ
XSL-FO 1.1には「改訂バー」という、行単位、段落単位のdiffを分かりやすく表示するためのオブジェクトがあります。このオブジェクト、直感的には互い違いをやらかしそうですが、しません。
...
<fo:change-bar-begin />
<fo:block> ...
<fo:change-bar-end />
...
</fo:block>
<fo:change-bar-begin />
と<fo:change-bar-end />
は構造的にはちゃんと閉じてるんですね。
他に、XML IDEのOxygen Editorなどでは任意の箇所を囲うためにProccessing-instruction命令で改訂バーのようなstartとendを使います。<??>
のアイツです。XMLを維持しつつ構造も飛び越えなきゃならないという要求に応えるとこんなことに。
Discussion
@disable-escape-escaping="true"
や<![CDATA]>
なしでもできました。…すみません。ちょっと何かやってみたかったもので…
コメントありがとうございます。
のコード内で使ってるの≺
PRECEDSっぽいんですが。<del><
じゃないのでXSLTはそのまま通して、変換後Webの画面に置くときあたりにFiddleくんによって文字が変更されている気がします。</del><ins>Fiddleはおかしくないですね。</ins><
か<xsl:element>
がないとXMLタグと思われないのでFiddle の XSL を下にスクロールすると…
小ネタには小ネタということで 😀
あー、ちゃんと見てませんでした。Fiddleがおかしいという話ではありませんでしたね。先のコメントを修正します。