なんか***基礎文法マスターなるものが流行っているそうなのでやってみる。
2010-02-02 19時追記>
- ことの発端はこちら→ Perl基礎文法最速マスター
- id:tt_clownさんによるまとめ記事はこちら → はてな的プログラミング言語人気ランキング
1. 基礎の基礎
XSLTとは、XML文書をXML文書もしくはプレーンテキストに変換するためのルールをXMLで記述する変換用言語です。
2007年に勧告が出されたXSLT version 2.0 はXSLT version 1.0 と比べて、複数の入出力文書の取り扱い、変数の型指定、sequenceのサポート、ユーザ関数定義などが追加されています。
プログラミング言語としてみた場合は、関数型言語属だと思います
詳細な仕様は以下のリンクから
- XSL Transformations (XSLT) Version 2.0 -- XSLTの仕様
- XML Path Language (XPath) 2.0 -- XSLTで使用するXPath言語の仕様
- XQuery 1.0 and XPath 2.0 Functions and Operators -- XPathで定義されている関数と演算子の仕様
- XQuery 1.0 and XPath 2.0 Data Model (XDM) -- XSLT, XPath で使用するデータの型などの仕様
XSLTプロセッサはとりあえず Saxon 使っときゃいいんじゃないかな
2. 基本文法
基本的にはXSLTで変換の流れを記述し、XSLTの各要素の属性値として記述されるXPath式で変換対象の取得や加工を行います
<?xml version="1.0" encoding="utf-8"?>
<!-- root要素の名前空間宣言はこのままコピペするといいです -->
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="xsl xs fn"
>
<!-- 出力文書のフォーマットを指定します。 xml, html, xhtml, text のどれかです -->
<xsl:output method="xml" />
<xsl:template match="/"> <!-- 入力文書のルートにマッチし、変換を行います -->
<!-- ルート要素がtestで、入力文書のtextを内容として持つXML文書を作成します -->
<test><xsl:value-of select="." /></test>
</xsl:template>
</xsl:stylesheet>
3. 実行
各XSLTプロセッサのドキュメントを参照してください。(ぇー
参考までに、Saxon 9.x on Java の場合は
c:\> java -jar saxon9.jar -xsl:スタイルシート.xsl -s:変換元XMLドキュメント.xml [-o:出力ファイル名]
4. コメント
XMLコメント <!-- -->
を使います。
5. メッセージ出力
xsl:message
要素で出力文書とは別にメッセージを出力できます。メッセージが出力される場所はXSLTプロセッサ依存です。
<!-- 変数 i の内容をメッセージ出力 -->
<xsl:message select="$i" />
<!-- terminate属性を指定すると、メッセージ出力後に変換処理を停止します -->
<xsl:message terminate="yes">何かエラー!</xsl:message>
6. 変数
変数は xsl:variable
要素で宣言・定義します。 変数の有効範囲は親要素で囲まれた範囲です。宣言・定義は同時に行わなければならず、後で内容を変更することはできません。
name属性で変数名を、as属性で型を指定します。変数の内容はselect属性に書かれたxpath式か、要素内容です。
変数やリテラルの演算や関数適用はXPath式内で行います。
<!-- i という名前の xs:integer型の変数を宣言・定義する -->
<xsl:variable name="i" as="xs:integer" select="1" />
<!-- XML断片を変数に持つこともできます -->
<xsl:variable name="elem" as="element()">
<root><parent><child>YO HO!</child></parent></root>
</xsl:variable>
7. 数値型
xs:integer
やxs:double
など様々な数値型が 用意されています。
四則演算+α
<xsl:value-of select="$i + 1" /> <!-- 加算 -->
<xsl:value-of select="$i - 1" /><!-- 減算 -->
<xsl:value-of select="$i * 2" /><!-- 乗算 -->
<xsl:value-of select="$i div 2" /><!-- 除算 -->
<xsl:value-of select="$i idiv 2" /><!-- 除算(商) -->
<xsl:value-of select="$i mod 2" /><!-- 除算(余り) -->
8. 文字列型
xs:string
型です。
<!-- xpath式中のリテラルはシングルクオートかダブルクオートで囲みます -->
<xsl:value-of select="'abcde'" />
<xsl:variable name="str" as="xs:string">要素内容ならそのまま書けます</xsl:variable>
文字列操作
<!-- 結合 -->
<xsl:value-of select="fn:concat('a', 'b', 'c')" /> <!-- abc -->
<xsl:value-of select="fn:string-join('a', 'b', 'c', ',')" /> <!-- a,b,c -->
<!-- 分割 -->
<xsl:value-of select="fn:tokenize('a,b, c', ',\s*')" /> <!-- ('a', 'b', 'c') -->
<!-- 長さ -->
<xsl:value-of select="fn:string-length('abcde')" /> <!-- 5 -->
<!-- 部分文字列 -->
<xsl:value-of select="fn:substring('abcde', 3)" /> <!-- cde -->
<xsl:value-of select="fn:substring('abcde', 3, 2)" /> <!-- cd -->
<!-- 検査 -->
<xsl:value-of select="fn:contains('abcde', 'bcd')" /> <!-- true -->
<xsl:value-of select="fn:starts-with('abcde', 'abc')" /> <!-- true -->
<xsl:value-of select="fn:matches('abcde', '\d+')" /> <!-- false -->
9. sequece型
任意の型に対する sequece を作成できます。型名の後ろに ?
(要素数は0か1), *
(要素数は0以上), +
(要素数は1以上) のいずれかをつけます。要素数が合わない場合はエラーです。また、参照する際のインデクスは1から始まります
<!-- sequence型 -->
<xsl:variable name="sa" as="xs:string*" select="('a', 'b', 'c')" />
<!-- xsl:sequece を使って作成することも出来る -->
<xsl:variable name="ia" as="xs:integer+">
<xsl:sequence select="1" />
<xsl:sequence select="0" />
<xsl:sequence select="9" />
</xsl:variable>
<!-- to演算子を使って整数のsequenceを生成できる -->
<xsl:variable name="ia2" as="xs:integer*" select="1 to 3" /> <!-- (1, 2, 3) -->
sequece 操作
<!-- 先頭を取り出す -->
<xsl:value-of select="$sa[1]" />
<!-- 結合 -->
<xsl:value-of select="(1,2,3), (4,(5,6))" /> <!-- (1,2,3,4,5,6) -->
<!-- 走査 -->
<xsl:value-of select="fn:index-of($sa, 'b')" /> <!-- 2 -->
<!-- 検査 -->
<xsl:value-of select="fn:existst($sa)" /> <!-- true -->
<xsl:value-of select="fn:empty($sa)" /> <!-- false -->
<!-- 削除 -->
<xsl:value-of select="fn:remove($sa, 2)" /> <!-- ('a', 'c') -->
<!-- 反転 -->
<xsl:value-of select="fn:reverse($sa)" /> <!-- ('c', 'b', 'a') -->
<!-- 部分sequence -->
<xsl:value-of select="fn:subsequence($sa, 2, 2)" /> <!-- ('b', 'c') -->
10. 辞書型
ありません どうしても欲しい場合は、element()
型変数で代用します。
<xsl:variable name="dict" as="element()">
<dict>
<key1>VALUE1</key1>
<key2>VALUE2</key2>
</dict>
</xsl:variable>
<xsl:value-of select="$dict//key1" /> <!-- VALUE1 -->
11. 制御構造
xsl:template
match
属性内のXPath式にマッチするXMLノードを変換するルールを子要素に記述します。
xsl:param
要素を記述して受け取るパラメタを宣言することもできます。
<!-- foo要素(ルート要素)の子要素である2番目のbar用の子要素であるfobar属性が'hoge'であるbaz要素 を変換する -->
<xsl:template match="/foo/bar[2]/baz[@fobar='hoge']">
<xsl:text>変換結果</xsl:text>
</xsl:template>
xsl:apply-templates
select
属性内のXPath式の内容にマッチするxsl:template
を適用します。子要素にxsl:with-param
を記述することでパラメタを渡すことも出来ます
<xsl:apply-templates select="/foo">
<xsl:with-param name="param1" as="xs:integer" select="1" />
<xsl:with-param name="param2" as="xs:string">パラメータ</xsl:with-param>
</xsl:apply-templates>
xsl:if
test
属性内のXPath式が真と見なされる場合、要素内容を評価します。他の言語でのelseに相当するものを使いたい場合は後述のxsl:choose
を使います
<xsl:if test="$i = 1">
<xsl:text>$i は 1 です。</xsl:text>
</xsl:if>
xsl:when
子要素として1個以上のxsl:when
要素と 0個か1個のxsl:otherwise
を記述します。
test
属性内のXPath式が真と見なされる最初のxsl:when
要素の内容が評価されます。
どのwhenにも引っかからなかった場合、otherwiseがあればotherwiseの内容が評価されます。
<xsl:choose>
<xsl:when test="$i = 1">
<xsl:text>$i は 1 です</xsl:text>
</xsl:when>
<xsl:when test="$i gt 1">
<xsl:text>$i は 1 より大きいです</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>$i は 1より小さいです</xsl:text>
</xsl:otherwise>
</xsl:choose>
xsl:for-each
select
属性内のXPath式で示されるnodesetもしくはsequenceを巡回して処理します。
for-each内では現在の要素はXPath式.
で取得できます。
また、for-eachの第1子要素としてxsl:sort
要素を置くと、ソートしてから巡回します
<!-- nodeset の巡回 -->
<xsl:for-each select="/foo/bar">
<xsl:value-of select="@id" /> <!-- 各bar要素のid属性値を出力 -->
</xsl:for-each>
<xsl:for-each select="(3,2,1)">
<xsl:sort />
<xsl:value-of select="." /> <!-- 順に 1 2 3 を出力 -->
</xsl:for-each>
12. 呼び出し可能template・ユーザ関数
xsl:template, xsl:call-template
match
属性でなく、name
属性を指定すれば、呼び出し可能なtemplateを作成できます。
というか、明示的にxsl:call-tempalte
で呼び出さないと、動いてくれません。
xsl:apply-templates
と同様、にwith-param
でパラメタを渡せます
<-- ↓呼び出し側 -->
<xsl:template match="/foo">
<xsl:call-template name="hoge">
<xsl:with-param name="p1" select="123" />
</xsl:call-template>
</xsl:template>
<!-- ↓がcallable template -->
<xsl:tempalte name="hoge">
<xsl:param name="p1" as="xs:integer" />
<xsl:value-of select="$p1 * 2" />
</xsl:template>
xsl:function
XPath式中で呼び出し可能な関数を定義します。as
属性で戻り値の型を指定し、要素内の評価結果が関数の戻り値になります。
ユーザ関数もどこかの名前空間に属していないといけないので注意してください
<-- 呼び出し側 -->
<xsl:template match="/">
<xsl:for-each select="my:func(99)">
<xsl:value-of select="." /><xsl:text>,</xsl:text>
</xsl:for-each>
</xsl:template>
<!-- xmlns:my が適切に設定されていると仮定 -->
<xsl:function name="my:func" as="xs:integer*">
<xsl:param name="p1" as="xs:integer" />
<!-- 結果がsequenceならxsl:sequenceを使用します -->
<xsl:sequence select="1 to $p1" />
</xsl:function>
13. 入出力
基本的な入力はスタイルシート呼び出し時に指定されたXML文書ですが、document()
関数でXML文書を、unparsed-text()
でその他のテキスト文書を読み込むことが出来ます
基本的な出力先はXSLTプロセッサ依存ですが、xsl:result-document
要素を使って出力先を指定することができます
<xsl:variable name="w3c" as="document()" select="document('http://www.w3.org')" />
<xsl:variable name="w3c_text" as="xs:string" select="unparsed-text('http://www.w3.org/')" />
<xsl:result-document href="another_output.txt" method="text">
<xsl:value-of select="$w3c//title" />
<xsl:value-of select="$w3c_text" />
</xsl:result-document>
また、xsl:import
やxsl:include
で他のXSLT文書を取り込めたりしますが、適用ルールとかちょっとややこしいので割愛
14. 知っておくと便利なこと
スタイルシートのルート要素を出力結果のルート要素にできる.(<xsl:template match="/"></xsl:template>
の子要素として扱われる
<!-- XSLT仕様より引用 -->
<html xsl:version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Expense Report Summary</title>
</head>
<body>
<p>Total Amount: <xsl:value-of select="expense-report/total"/></p>
</body>
</html>
sequece様のデータに対してaccumulate的なことをしたい場合は、 functionかnamed templateの再帰呼び出しで何とかする。
<xsl:fucntion name="my:sum" as="xs:integer">
<xsl:param name="n" as="xs:integer*" />
<xsl:param name="m" as="xs:integer" />
<xsl:choose>
<xsl:when test="fn:exists($n)">
<xsl:value-of select="my:sum(fn:remove($n,1), $n[1] + $m)" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$m" />
</xsl:otherwise>
</xsl:choose.
</xsl:function>
<!-- 呼び出し -->
<xsl:value-of select="my:sum( (1,3,5,7), 0 )" />
xsl:variable
子要素など、仕様で "<-- Sequence Constructor -->"って書いてあるところには、value-ofやsequence等のデータ作成用要素のみならず、for-eachやchoose,apply-templatesなど、制御用のXSLT要素も記述できる。variableの定義中にローカルなvariableを作って云々とかも可能
...疲れた
コメントする