Notice : 内容無保証。禁無断転載。引用、リンク自由。

XSLT Tips

目次

概要 : 2004-10-07
はじめに
適用範囲
使用ツール
その他
基本構造 : 2004-03-28
XML 文書の基本構造
XSLT ファイルの基本構造
XML 文書から XHTML 文書を出力する例
おまけ : XML 文書から LaTeX ソースファイルを出力する例
小技 : 2004-10-14
属性の省略判定
空要素の展開抑制
変数
文書構造の変換
自分自身の参照
制御構造 : 2003-12-17
ループ
移植 : 2004-02-10
関数
一時変数を隠す
名前空間 : 2004-01-07
不要な名前空間宣言
exclude-result-prefixes で名前空間宣言を消す
xsl:copy と exclude-result-prefixes
xsl:element で名前空間宣言を消す
おまけ : xsl:element での空要素の展開を避ける
おまけ : 展開名の表示用 XSLT
実例 : 2004-01-28
XSLT Tips (このページ)
日記用
半角カナ→全角カナ変換テンプレート
同じ誕生日になる確率
未解決 : 2004-03-02
飛べないリンク
要確認
おまけ : 2004-02-10
xsl:output の encoding
msxsl のコマンドラインでのパラメタの渡し方
サンプル .html 作成用メイクファイル
リンク : 2004-03-27

概要

[概要] はじめに
(last modified : 2003-12-17)

このページで示している XSLT のサンプルコードについては、 そのままであろうと変更なさろうと、ご自由に利用いただいてかまいません。 ただし、内容の正しさや運用の結果については何も保証しませんので、 ご利用の際には充分なテストを行われることをおすすめいたします。

[概要] 適用範囲
(last modified : 2004-01-26)

このページで取り上げる XML 文書の大部分は、UA での表示を前提としたものである。

UA が XML 文書を表示するまでの流れの例

XML → (XSLT でデータ構造を変換) → XHTML → (CSS で書式を設定) → 表示

このページでは上記の流れ中、XML 文書を XHTML 文書に変換するための XSLT を題材とする。 が、初心者用の入門ページであることは意図しない。 ( ここには自分が悩んで、解決した事しか書かないので、話題が偏ってます。 もっと系統立った解説ページへは、[リンク] からどうぞ。 ) 既に XSLT を使い始めていて、具体的な疑問点を持っている方へのヒントぐらいなら有るかも。

[概要] 使用ツール
(last modified : 2004-10-07)

UA で直接 XML 文書をブラウズできる場合、変換結果の XHTML 文書を目にすることは無いと思われる。 ここでは変換結果を示すために XSLT プロセッサとして、msxsl.exe を使用した。

サンプルの表示確認には以下の UA を使用している。

  • Internet Explorer 6.0
  • (2004-02-13 削除) Mozilla 1.3
  • Mozilla 1.6
  • (2004-02-13 削除) Mozilla Firebird 0.7
  • Mozilla Firefox 1.0 PR (Firefox/0.10.1)
  • Opera 7.23 ( XSLT 非対応なので、 msxsl.exe での変換結果の表示のみを確認 )

ついで。 メイクには Borland MAKE Version 5.2 ( たしか BC++ 5.5 に付属してたやつ ) を、XML/XSLT 編集にはテキストエディタ ( 秀丸 ) を使用している。

[概要] その他
(last modified : 2003-12-17)

このページで変換結果として表示している例は、生の変換結果に改行/インデントを追加したものである。 生の変換結果はリンク先の HTML ファイル ( ソース ) を参照のこと。

基本構造

(注) 以下は自分が使ってるものしか書いていない不完全なものである。
( 逆に、このページ程度の XHTML を自動生成するならこれぐらいで充分かと思われる。 )

[基本構造] XML 文書の基本構造
(last modified : 2004-02-23)

(注) 完全な構造は、 「Extensible Markup Language (XML) 1.0 (Third Edition) W3C 勧告 (2004-02-04)」 の、 「2 Documents」 を参照のこと。

<?xml version="1.0" encoding="Shift_JIS"?>
<?xml-stylesheet type="application/xml" href="[XSL ファイル名]"?>

<[要素名] [属性名="属性値"]>
  <!-- : -->
</[要素名]>
[XML 文書の基本構造] xml-stylesheet の type について

IE6 ではスタイルシートの MIME タイプを text/xsl と指定しなければ XHTML への変換が行われなず、 ソース(XML) が表示されてしまう。 ( MS の独自仕様なのか? text/xsl がどこでどう定義されたものなのか、調査不足でよく判らない。 )

(2004-03-28T22:49:59+09:00 追記)

XMLクイックリファレンス 第2版」 によると、text/xsl というのは、Microsoftの想像の産物 だそうである。 この情報は千葉氏より教えていただきました。感謝します。

MS の msxsl では application/xml のままでちゃんと変換できるので、 IE でもそのうち application/xml で変換できるようになるんだろう。 ( 希望的観測 )

と思ってたら、 今後のIEの改善には、その根底にあるOSの強化が必要になる (→ CNET Japan : マイクロソフト、IEスタンドアローン版廃止へ ) って、本気かしらん。あー。IE はもういいや。

[基本構造] XSLT ファイルの基本構造
(last modified : 2003-08-22)

(注) 完全な構造は、 「XSL Transformations (XSLT) Version 1.0 W3C 勧告 (1999-11-16)」 の、 「2.2 Stylesheet Element」 を参照のこと。

<?xml version="1.0" encoding="Shift_JIS" ?>

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns="http://www.w3.org/1999/xhtml"
>

  <!-- インポートするファイルの指定 -->

    <xsl:import href="[ファイル名]" />

  <!-- 出力ファイルの形式の指定 (この例では XHTML 1.1) -->

    <xsl:output
      method="xml"
      encoding="Shift_JIS"
      omit-xml-declaration="no"
      doctype-public="-//W3C//DTD XHTML 1.1//EN"
      doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
      indent="yes"
    />

  <!-- コマンドラインで指定されるパラメタの定義 (無ければ略) -->
  <!-- (参) msxsl のコマンドラインでのパラメタの渡し方 -->

    <xsl:param name="[パラメタ名]">[デフォルト値]</xsl:param>
    <!-- : 他のパラメタ定義 -->

  <!-- グローバル変数の定義 (無ければ略) -->

    <xsl:variable name="[変数名]">[値]</xsl:variable>
    <!-- : 他の変数定義 -->

  <!-- テンプレート -->

    <xsl:template match="[要素名]">
      <!-- : -->
    </xsl:template>

    <!-- : 他のテンプレート定義 -->

  <!-- 名前付きテンプレート (無ければ略) -->

    <xsl:template name="[テンプレート名]">
      <xsl:param name="[パラメタ名]">[デフォルト値]</xsl:param>
      <!-- : -->

      <!-- : -->
    </xsl:template>

    <!-- : 他の名前付きテンプレート定義 -->

</xsl:stylesheet>
[基本構造] XML 文書から XHTML 文書を出力する例
(last modified : 2003-08-22)
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml-stylesheet type="application/xml" href="simple.xsl"?>

<ra:sample
  xmlns:ra = "http://www5a.biglobe.ne.jp/~rarin/xml/ra"
  title = "XSLT Sample simple"
/>
<?xml version="1.0" encoding="Shift_JIS" ?>

<xsl:stylesheet
  version="1.0"
  xmlns:ra  = "http://www5a.biglobe.ne.jp/~rarin/xml/ra"
  xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
  xmlns     = "http://www.w3.org/1999/xhtml"
  exclude-result-prefixes="ra"
>

  <xsl:output
    method="xml"
    encoding="Shift_JIS"
    omit-xml-declaration="no"
    doctype-public="-//W3C//DTD XHTML 1.1//EN"
    doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
    indent="yes"
  />

  <xsl:template match="/ra:sample">
    <html xml:lang="ja" dir="ltr">

      <head>
        <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=Shift_JIS" />
        <title><xsl:value-of select="@title" /></title>
      </head>

      <body>
        <h1><xsl:value-of select="@title" /></h1>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE html
  PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
>

<html xml:lang="ja" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">

  <head>
    <meta
      http-equiv="Content-Type"
      content="application/xhtml+xml; charset=Shift_JIS"
    />
    <title>XSLT Sample simple</title>
  </head>

  <body>
    <h1>XSLT Sample simple</h1>
  </body>

</html>
[基本構造] おまけ : XML 文書から LaTeX ソースファイルを出力する例
(last modified : 2004-03-05)

XSLT では XML 文書を XHTML 文書にしか変換できないというわけでは無い。 先の XML 文書 (→ sample/simple.xml ) から LaTeX ソースファイルを出力する XSLT の例。

( 手元に LaTeX の処理系を持っていないので、 正しい LaTeX ソースファイルになってるのか確認できてません。 )

XML/HTML 文書以外を出力する時は、 xsl:outputmethodtext にしておくこと。 ( そうしないと、 '<'、 '>'、 '&'、 等がそれぞれ、 '&lt;'、 '&gt;'、 '&amp;'、 等にエスケープされてしまうので。 )

<?xml version="1.0" encoding="Shift_JIS" ?>

<xsl:stylesheet
  version="1.0"
  xmlns:ra  = "http://www5a.biglobe.ne.jp/~rarin/xml/ra"
  xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
>
  <xsl:import href="const.xsl" />

  <xsl:output
    method="text"
    encoding="Shift_JIS"
    omit-xml-declaration="yes"
    indent="yes"
  />

  <!--
    $br は改行コード。 const.xsl 中で、
      <xsl:variable name="br" select="'&#x0a;'" />
    と定義してある。
    変換結果中に改行を明示的に追加したい場合、&#x0a; を出力してやれば良い
  -->

  <xsl:template match="/ra:sample">
    <xsl:value-of select="concat(
      '\documentstyle{jarticle}', $br,
      '\title{', @title, '}', $br,
      '\author{ら &lt;simple_latex.xsl&gt;}', $br,
      '\date{\today}', $br,
      '\begin{document}', $br,
      '\maketitle', $br,
      '\end{document}', $br
    )" />
  </xsl:template>

</xsl:stylesheet>
\documentstyle{jarticle}
\title{XSLT Sample simple}
\author{ら <simple_latex.xsl>}
\date{\today}
\begin{document}
\maketitle
\end{document}

小技

[小技] 属性の省略判定
(last modified : 2004-01-26)

(注) この項は、Mozilla 1.3 と msxsl ではこうなったというだけで、仕様書上で確認できていない。
( 「XML Path Language (XPath) Version 1.0 W3C 勧告 (1999-11-16)」 の 「3.4 Booleans」 あたりがそれっぽいんだけど、確信が持てない。 )
実装依存の可能性があるため、適用時にはちゃんとテストすること。
( テストにはこの項のサンプルを使用すると良い。 )

属性が省略された場合、空文字列との比較 ――

test = "@attr  = ''"
test = "@attr != ''"

は共に "偽" となってしまうため、これでは属性が省略されていることを判定できない。

属性が省略された場合、 test = "@attr" のように、 @attr を直接 bool 値として扱うと "偽" と判定できる。 よって、属性が省略されたことを判定したい場合は、

test = "not(@attr)"

とすれば良い。

属性の省略と空文字列の指定を同列に扱いたい場合は、 string() 関数で @attr を文字列に変換した後で空文字列と比較すると良い。 例えば、

test = "string(@attr) = ''"

は、 属性が省略されている場合でも、 属性に空文字列が指定されている場合でも、 どちらでも "真" と判定される。

サンプル
XML: sample/default.xml
XSLT: sample/default.xsl
変換結果: sample/default.html
[小技] 空要素の展開抑制
(last modified : 2003-08-18)

(注) この項は、msxsl ではこうなったというだけで、仕様書上で確認できていない。
実装依存の可能性があるため、適用時にはちゃんとテストすること。

なんかもっと 「まとも」 な方法があるような気がするけど思いつかないので公開してみるテスト。

[空要素の展開抑制] xsl:copy での空要素の展開を抑える

XML 文書を変換せずそのまま出力する場合、以下のテンプレートが使用できる。

<xsl:template match="* | @* | text()">
  <xsl:copy>
    <xsl:apply-templates select="* | @* | text()" />
  </xsl:copy>
</xsl:template>

ところが上記テンプレートは、例えば <br /> のような空要素を <br></br> のように展開する副作用も持つ。 ( 理由が不明。 msxsl の実装依存かも。 )

XML として見れば両者は全く同等の意味を持つが、 UA の実装 ( 特に XML以前の古い UA ) によっては、上記を <br /><br /> と誤解釈し、期待した表示を得られない場合がある。 ( 実験できた範囲では mozilla 1.3 は正しく解釈したが、IE6、Opera 7.11 は誤解釈した。 )

空要素について、 要素 ( * ) と 内容 ( text() ) を xsl:copy の対象から外すことで展開を避けられる。 ( ツリーがこれ以上伸びない訳で、分かるような気もするけど、ちゃんとした理由が不明。 msxsl の実装依存かも。 ) 上記テンプレートと併せて例えば以下のようなテンプレートを使えば良い。

<xsl:template match="br | hr | img">
  <xsl:copy>
    <xsl:apply-templates select="@*" />
  </xsl:copy>
</xsl:template>

上記は br, hr, img について、 属性 ( @* ) のみをコピーするよう指定した例である。

[空要素の展開抑制] xsl:element での空要素の展開を抑える

xsl:elementxsl:copy-of を使う以下のテンプレートでも XML 文書を変換せずそのまま出力できる。 だがこのテンプレートも前項の xsl:copy 版と同様に空要素を展開する副作用を持っている。 ( 理由が不明。 msxsl の実装依存かも。 )

<xsl:template match="*">
  <xsl:element name="{name()}">
    <xsl:copy-of select="@*" />
    <xsl:apply-templates />
  </xsl:element>
</xsl:template>

空要素について、 xsl:apply-templates を止めれば展開を避けられる。 ( これもツリーがこれ以上伸びない訳で、分かるような気もするけど、ちゃんとした理由が不明。 msxsl の実装依存かも。 ) 上記テンプレートと併せて、例えば以下のようなテンプレートを使えば良い。

<xsl:template match="br | hr | img">
  <xsl:element name="{name()}">
    <xsl:copy-of select="@*" />
    <!-- <xsl:apply-templates /> -->
  </xsl:element>
</xsl:template>
実例
XSLT Tips (このページ)default.xsl
[小技] 変数
(last modified : 2003-06-04)

xsl:variable は、variable といいつつ、 定義時に設定した値を生存期間中に変更できない定数である。 例えば、

<xsl:variable name="n" select="16" />

と書くと、$n の値は生存期間中そのスコープ内ではずっと 16 のままである。

条件に応じて初期値を変えたい場合は select を使わずに、 xsl:if あるいは xsl:choose と組み合わせる。 例えば、

<xsl:variable name="n">
  <xsl:choose>
    <xsl:when test = "[条件 1]">[条件 1 が成立した時の値]</xsl:when>
    <!-- : -->
    <xsl:when test = "[条件 n]">[条件 n が成立した時の値]</xsl:when>
    <xsl:otherwise>[どの条件にも当てはまらなかった場合の値]</xsl:otherwise>
  </xsl:choose>
</xsl:variable>

のように書く。

サンプル
XML: sample/variable.xml
XSLT: sample/variable.xsl
変換結果: sample/variable.html
[小技] 文書構造の変換
(last modified : 2003-12-05)

フラットな構造から階層構造への変換例。

<diary>
  <topic date="2003-12-05T11:25:16+09:00">1</topic>
  <topic date="2003-12-05T12:26:57+09:00">2</topic>

  <topic date="2004-01-01T15:27:56+09:00">3</topic>
  <topic date="2004-01-01T16:28:16+09:00">4</topic>
</diary>

のようなベタな構造を、

<diary>
  <year n="2003">
    <topic date="2003-12-05T11:25:16+09:00">1</topic>
    <topic date="2003-12-05T12:26:57+09:00">2</topic>
  </year>

  <year n="2004">
    <topic date="2004-01-01T15:27:56+09:00">3</topic>
    <topic date="2004-01-01T16:28:16+09:00">4</topic>
  </year>
</diary>

のように、年ごとに階層化する。 ( 詳細はサンプル参照のこと。気が向いたら解説書きます。 )

サンプル
XML: sample/pttp.xml
XSLT: sample/pttp.xsl
変換結果: sample/pttp_.xml
実例
日記用 (<xsl:template match="diary"> : 年だけでなく、月、日についても階層化している)
[小技] 自分自身の参照
(last modified : 2004-10-14)

XSLT 中で、自分自身の要素や属性を参照したい場合、document("") を使う。

例えば xsl:output 要素の encoding 属性を参照したい場合は、

<xsl:variable name="charset" select="document('')/xsl:stylesheet/xsl:output/@encoding" />

のようにすれば良い。

サンプル : CSS の @charset を、 XSLT 自身の xsl:output 要素の encoding 属性を元に決定する
XML: sample/css.xml
XSLT: css/css.xsl
DTD: css/css.dtd
変換結果: sample/css.css

制御構造

[制御構造] ループ
(last modified : 2003-12-17)

名前付きテンプレートを再帰呼び出しすることで処理を繰り返す。 その際、引数をループ制御変数として使う。

  • 呼び出し側
<xsl:template match="/">
  <xsl:call-template name="loop">
    <xsl:with-param name="ct" select="10" />
  </xsl:call-template>
</xsl:template>
  • 名前付きテンプレート側
<xsl:template name="loop">
  <xsl:param name="ct">0</xsl:param> <!-- パラメタ : ループ制御用カウンタ -->

  <xsl:if test="0 &lt; $ct"> <!-- カウンタが 0 より大きい時だけ -->
    <!--
      :
      ループ中にやりたい処理
      :
    -->

    <!-- 引数の値を 1減らして再帰呼び出し -->
    <xsl:call-template name="loop">
      <xsl:with-param name="ct" select="$ct -1" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>
サンプル
XML: sample/loop.xml
XSLT: sample/loop.xsl
変換結果: sample/loop.html
実例
半角カナ→全角カナ変換テンプレート
同じ誕生日になる確率

移植

[移植] 関数
(last modified : 2004-01-28)

関数のリターン値を名前付きテンプレートで実現するには、 xsl:value-of を生で使うと良い。

以下、C言語からの移植例。

  • C : 関数
int inc(int x) {
  return x+1 ;
}
  • C : 呼び出し側
int ans = inc(0) ;
  • XSLT : 名前付きテンプレート
<xsl:template name="inc">
  <xsl:param name="x" />
  <xsl:value-of select="$x+1" />
</xsl:template>
  • XSLT : 呼び出し側
<xsl:variable name="ans">
  <xsl:call-template name="inc">
    <xsl:with-param name="x" select="0" />
  </xsl:call-template>
</xsl:variable>
実例
XSLT (曜日計算テンプレート): ../ra/calendar.xsl
XSLT (呼び出し側): ../ra/diary.xsl
[移植] 一時変数を隠す
(last modified : 2004-02-10)

XSLT の制限から、移植にあたって元のソースでは不要だった一時変数が必要になる場合がある。

例えば以下の C コードのように、関数呼び出しだけで代入文が終わらない場合、

  • C : 呼び出し側
int x = foo() +1 ;

xsl:call-template は xsl:variable の select 中で使えないので、 xsl:call-template の戻り値を保存するための一時変数が必要になる。

  • XSLT : 呼び出し側
<xsl:variable name="ret">
  <xsl:call-template name="foo" />
</xsl:variable>

<xsl:variable name="x" select="$ret +1" />

ところが上の書き方では、規模が大きくなった場合、一時変数の命名と管理に悩まされることになる。 ( XSLT では変数への再代入ができないせいもあり、一時変数の数が増えるため。 )

  • C : 呼び出し側
int x = foo() +1 ;
int y = bar() +1 ;
  • XSLT : 呼び出し側
<xsl:variable name="ret">
  <xsl:call-template name="foo" />
</xsl:variable>
<xsl:variable name="x" select="$ret +1" />

<!-- これ以降、 ret の値は誰も使わないのだが…… -->

<xsl:variable name="ret_2">  <!-- 変数 ret に再代入できないので、新たな一時変数が必要になってしまう -->
  <xsl:call-template name="bar" />
</xsl:variable>
<xsl:variable name="y" select="$ret_2 +1" />

一時変数が必要な範囲でローカルに宣言すれば、名前の重複を気にする必要が無くなり、変数名の管理が楽になる。

  • XSLT : 呼び出し側
<xsl:variable name="x">
  <!-- 変数 ret をローカルに宣言する。 -->
  <xsl:variable name="ret">
    <xsl:call-template name="foo" />
  </xsl:variable>
  <xsl:value-of select="$ret +1" />
  <!-- 変数 ret のスコープはここまで。 -->
</xsl:variable>

<xsl:variable name="y">
  <!-- 前に宣言した 変数 ret のスコープ外なので、名前が同じでも二重宣言エラーにならない。 -->
  <xsl:variable name="ret">
    <xsl:call-template name="bar" />
  </xsl:variable>
  <xsl:value-of select="$ret +1" />
  <!-- 変数 ret のスコープはここまで。 -->
</xsl:variable>
サンプル
XML: sample/scope.xml
XSLT: sample/scope.xsl
変換結果: sample/scope.html

名前空間

[名前空間] 不要な名前空間宣言
(last modified : 2003-10-06)

変換結果には不要な名前空間の宣言が出力されてしまう例。

<?xml version="1.0" encoding="Shift_JIS"?>
<?xml-stylesheet type="application/xml" href="namespace_01.xsl"?>

<ra:sample
  xmlns:ra="http://www5a.biglobe.ne.jp/~rarin/xml/ra"
  xmlns="http://www.w3.org/1999/xhtml"
  title="XSLT Sample namespace 01"
/>
<?xml version="1.0" encoding="Shift_JIS" ?>

<xsl:stylesheet
  version="1.0"
  xmlns:ra="http://www5a.biglobe.ne.jp/~rarin/xml/ra"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns="http://www.w3.org/1999/xhtml"
>

  <xsl:output
    method="xml"
    encoding="Shift_JIS"
    omit-xml-declaration="no"
    doctype-public="-//W3C//DTD XHTML 1.1//EN"
    doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
    indent="yes"
  />

  <xsl:template match="/ra:sample">
    <html xml:lang="ja" dir="ltr">

      <head>
        <meta
          http-equiv="Content-Type"
          content="application/xhtml+xml; charset=Shift_JIS"
        />
        <title><xsl:value-of select="@title" /></title>
      </head>

      <body>
        <h1><xsl:value-of select="@title" /></h1>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

XML および XSLT 中では名前空間 ra を使用しているので、その名前空間宣言 xmlns:ra="http://www5a.biglobe.ne.jp/~rarin/xml/ra" が必要。

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE html
  PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
>

<html
  xml:lang="ja" dir="ltr"
  xmlns:ra="http://www5a.biglobe.ne.jp/~rarin/xml/ra"
  xmlns="http://www.w3.org/1999/xhtml"
>
  <head>
    <meta
      http-equiv="Content-Type"
      content="application/xhtml+xml; charset=Shift_JIS"
    />
    <title>XSLT Sample namespace 01</title>
  </head>

  <body>
    <h1>XSLT Sample namespace 01</h1>
  </body>
</html>

変換結果の XHTML では名前空間 ra を使っていないので、その名前空間宣言は不要。 にもかかわらず名前空間宣言が出力されてしまっている。

[名前空間] exclude-result-prefixes で名前空間宣言を消す
(last modified : 2003-10-06)

exclude-result-prefixes で不要な名前空間宣言を消せる例。

<?xml version="1.0" encoding="Shift_JIS" ?>

<xsl:stylesheet
  version="1.0"
  xmlns:ra="http://www5a.biglobe.ne.jp/~rarin/xml/ra"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns="http://www.w3.org/1999/xhtml"
  exclude-result-prefixes="ra"
>

  (略)

</xsl:stylesheet>

変換結果に不要な名前空間を xsl:stylesheet の属性 exclude-result-prefixes で指定してやる。

(略)

<html
  xml:lang="ja" dir="ltr"
  xmlns="http://www.w3.org/1999/xhtml"
>

  (略)

</html>

不要な名前空間宣言が消える。

[名前空間] xsl:copy と exclude-result-prefixes
(last modified : 2003-10-06)

xsl:copy がらみで exclude-result-prefixes が効かなくなる例。

(略)

<ra:sample
  xmlns:ra="http://www5a.biglobe.ne.jp/~rarin/xml/ra"
  xmlns="http://www.w3.org/1999/xhtml"
  title="XSLT Sample namespace 03"
>
  <p>
    xsl:copy でコピーされるノード。
    <br />
    (余計な名前空間宣言が付いてしまう。ソース参照のこと。)
  </p>
</ra:sample>
<?xml version="1.0" encoding="Shift_JIS" ?>

<xsl:stylesheet
  version="1.0"
  xmlns:ra="http://www5a.biglobe.ne.jp/~rarin/xml/ra"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns="http://www.w3.org/1999/xhtml"
  exclude-result-prefixes="ra"
>

  (略)

  <xsl:template match="/ra:sample">
    <html xml:lang="ja" dir="ltr">

      (略)

      <body>
        <h1><xsl:value-of select="@title" /></h1>
        <xsl:apply-templates />
      </body>
    </html>
  </xsl:template>

  <xsl:template match="* | @* | text()">
    <xsl:copy>
      <xsl:apply-templates select="* | @* | text()" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

変換方法が指定されていないノードは全てそのままコピーするように指定すると……。

(略)

<html
  xml:lang="ja" dir="ltr"
  xmlns="http://www.w3.org/1999/xhtml"
>

  (略)

  <body>
    <h1>XSLT Sample namespace 03</h1>
    <p xmlns:ra="http://www5a.biglobe.ne.jp/~rarin/xml/ra">
      xsl:copy でコピーされるノード。
      <br></br>
      (余計な名前空間宣言が付いてしまう。ソース参照のこと。)
    </p>
  </body>
</html>

コピーされた要素中、ルートノードに一番近いものの属性に名前空間宣言が現れてしまう。 例えば上の例で XML 文書に段落 ( <p> ) が複数あれば、段落ごとに名前空間宣言が現れ、 <html> の属性一つで済んでいた最初の例より鬱陶しいことになる。

xsl:copy が名前空間ノードまで複製するのは、XSL Transformations (XSLT) Version 1.0 で、 The namespace nodes of the current node are automatically copied (→ 7.5 Copying ) と述べられている通り、正しい挙動である。 しかし exclude-result-prefixes で指定した名前空間の宣言が最終出力に現れて良いのかどうかは良く判らない……。

( 横道 : xsl:copy<br /><br></br> に展開するのを抑制するには → xsl:copy での空要素の展開を抑える )

[名前空間] xsl:element で名前空間宣言を消す
(last modified : 2003-10-06)

xsl:elementlocal-name() だけを出力することで名前空間の宣言を消す例。

<?xml version="1.0" encoding="Shift_JIS" ?>

<xsl:stylesheet
  version="1.0"
  xmlns:ra="http://www5a.biglobe.ne.jp/~rarin/xml/ra"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:xhtml="http://www.w3.org/1999/xhtml"
  exclude-result-prefixes="xhtml ra"
>

  (略)

  <xsl:template match="/ra:sample">
    (略)
  </xsl:template>

  <xsl:template match="xhtml:*">
    <xsl:element name="{local-name()}">
      <xsl:copy-of select="@*" />
      <xsl:apply-templates />
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

元々 XHTML の要素なら、変換後の XHTML に名前空間までコピーしなくて良い。 ローカル名だけを持つ要素を作る。

ここで、XHTML の要素であることを明示するために新たな名前空間 xhtml を導入すると共に、名前空間 xhtml の宣言が変換結果に現れないようにするために、 exclude-result-prefixes="xhtml ra" と指定している。

(略)

<html
  xml:lang="ja" dir="ltr"
  xmlns="http://www.w3.org/1999/xhtml"
>

  (略)

  <body>
    <h1>XSLT Sample namespace 04</h1>
    <p>
      local-name() だけを出力したノード。
      <br></br>
      (余計な名前空間宣言が無くなっている。
      しかし、空要素が展開されている。ソース参照のこと。)
    </p>
  </body>
</html>

余計な名前空間の宣言は無くなった。 しかし、 xsl:copy の時と同様に <br /><br></br> に展開されている。

[名前空間] おまけ : xsl:element での空要素の展開を避ける
(last modified : 2003-10-06)

前項までで不要な名前空間宣言の削除については解決した。 残った問題 ―空要素の展開を抑止する方法― について考える。 ( msxsl 依存かも。 )

<?xml version="1.0" encoding="Shift_JIS" ?>

<xsl:stylesheet
  (略)
>

  (略)

  <xsl:template match="/ra:sample">
    (略)
  </xsl:template>

  <xsl:template match="xhtml:*">
    (略)
  </xsl:template>

  <xsl:template match="xhtml:br | xhtml:hr | xhtml:img">
    <!--
      以下のように xsl:apply-templates を抜くと展開されない。
      処理系 (msxsl) 依存かも。
    -->
    <xsl:element name="{local-name()}">
      <xsl:copy-of select="@*" />
      <!-- <xsl:apply-templates /> -->
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

展開を抑えたい要素 ( 上記の例ではとりあえず br, hr, img の三つ ) については、 xsl:apply-templates を行わない。

(略)

<html
  xml:lang="ja" dir="ltr"
  xmlns="http://www.w3.org/1999/xhtml"
>
  (略)

  <body>
    <h1>XSLT Sample namespace 05</h1>
    <p>
      local-name() だけを出力したノード。
      <br />
      (余計な名前空間宣言が無くなっている。
       空要素の展開が抑えられている。ソース参照のこと。)
    </p>
  </body>
</html>

満足できる変換結果が得られた。

参考
xsl:element での空要素の展開を抑える
実例
XSLT Tips (このページ)
[名前空間] おまけ : 展開名の表示用 XSLT
(last modified : 2004-01-07)

デバグ/学習用。 要素名、属性名の後に、[{URI}ローカル名] を出力する XSLT 。

  • 出力サンプル
<ra:sample [{http://www5a.biglobe.ne.jp/~rarin/xml/ra}sample]>

  <e1 [{}e1]
    a1 [{}a1] = ""
    ra:a2 [{http://www5a.biglobe.ne.jp/~rarin/xml/ra}a2] = ""
    xh:a3 [{http://www.w3.org/1999/xhtml}a3] = ""
  />

</ra:sample>
サンプル
XML: sample/show_namespace.xml
XSLT: sample/show_namespace.xsl
変換結果: sample/show_namespace.txt

実例

[実例] XSLT Tips (このページ)
(last modified : 2004-01-28)

このページは XSLT によって生成されている。 XSLT は xsl:for-each による目次の自動生成や、xsl:element による XHTML のタグ利用等の実例になっている。 ( 内容無保証。参考にする際には十分試験すること。 )

実例
XML (本体): xslt_tips.xml
XML (概要): s_abstract.xml
XML (基本構造): s_structure.xml
XML (小技): s_tips.xml
XML (制御構造): s_control.xml
XML (移植): s_transport.xml
XML (名前空間): s_namespace.xml
XML (実例): s_example.xml
XML (未解決): s_unsettled.xml
XML (おまけ): s_appendix.xml
XML (リンク): s_link.xml
XSLT (本体): ra.xsl
XSLT (定数): const.xsl
XSLT (MS依存): ms_script.xsl
XSLT (デフォルト): default.xsl
XSLT (用語集): glossary.xsl
XSLT (確率計算): same_birthday.xsl
変換結果 (HTML): xslt_tips.html(このページ)
メイクファイル: makefile
[実例] 日記用
(last modified : 2004-01-28)

日記 ( 「らの生活」 ) の HTML と RSS を XML 文書から自動生成するために使っている XSLT と メイクファイル。 XML 文書をフラットな構造に変更したため、XSLT 側が随分汚いことに……。

実例
XML: ../ra/index.xml
XSLT (HTML 用): ../ra/diary_v0200.xsl
XSLT (RSS 生成用): ../ra/index_rdf_v0200.xsl
XSLT (RSS 表示用): ../ra/rdf.xsl
変換結果 (HTML): ../ra/index.html
変換結果 (RSS): ../ra/index.rdf
メイクファイル: ../ra/makefile
おまけ (スキーマ): ../ra/diary.xsd(更新してないので、現状の XML と合ってません。)
[実例] 半角カナ→全角カナ変換テンプレート
(last modified : 2003-10-06)

最初冗談のつもりで作りはじめたんだけど、ループと文字列関数関係の実例になったので公開してみる。

実例
XML: sample/hk2zk.xml
XSLT (テンプレートのテスト用): sample/hk2zk.xsl
XSLT (テンプレート本体): hk2zk.xsl
変換結果 (HTML): sample/hk2zk.html
[実例] 同じ誕生日になる確率
(last modified : 2003-12-17)

ループの実例。計算精度については未確認。

実例
XML: ../ra/same_birthday.xml
XSLT: same_birthday.xsl
変換結果 (HTML): ../ra/same_birthday.html

未解決

(last modified : 2004-03-02)

XML 文書を直接ブラウズしている際、Mozilla 1.3 ではリンクがうまく働かず、ページ先頭に戻されてしまう事がある。 例えばこのページのXML版では、目次以降のリンクが働いていない。 ( IE6 では XML のままで問題なくリンクできている。 )

これが UA側の問題なのか XML/XSLT 側の問題なのか特定できていない。 解決方法も不明。

(2004-01-27 削除) (2004-01-26 追記)

解決したかも。 いろいろ試してみた結果、 id 属性を含む要素の前で改行しておけば良いようだ。 具体的にはこのページ生成用の XSLT ( 中のそれっぽいコメントの付いた付近 ) を参照のこと。 改行なしの XHTML 版で問題が無かったことから、 UA 側の問題っぽい気がするけど良く判らない。

(2004-01-27 追記)

さらにいろいろ試してみた結果、↑ の改行は本当の原因では無くて、

飛べる例
XSLT: sample/link_good.xsl
XML: sample/link_good.xml
飛べない例
XSLT: sample/link_bad.xsl
XML: sample/link_bad.xml

のように、代替スタイルシートを指定するだけで飛べなくなってしまった。 もう、さっぱり理由が判らない。

(2004-02-13 追記)

別のバージョンでも試してみた結果、

× : Mozilla 1.3
× : Mozilla Firebird 0.7
○ : Mozilla 1.6
○ : Mozilla Firefox 0.8 (Revontulet)

となった。 UA 側の問題だったらしい。 ( “Bugzilla”、 “バグジラ” を調べなおしてみよう……。 )

[未解決] 要確認
(last modified : 2003-12-17)

さしあたって ( 自分では ) 困ってはいないペンディング事項。

おまけ

[おまけ] xsl:output の encoding
(last modified : 2003-10-06)

Shift_JIS の .xml と .xsl から UTF-8 の .html を出力する。

サンプル
XML: sample/encoding.xml
XSLT: sample/encoding.xsl
変換結果 (HTML): sample/encoding.html
実例
日記用の XSLT (RSS用) : ../ra/index_rdf.xsl
[おまけ] msxsl のコマンドラインでのパラメタの渡し方
(last modified : 2003-10-06)

XSLT 中のパラメタ ( <xsl:param name="パラメタ名">デフォルト値</xsl:param> ) の値はコマンドラインから指定する。 msxsl でのパラメタの渡し方は以下のようになる。

  • コマンドラインの最後で、パラメタ名="パラメタ値" のように指定する。
  • " の代わりに ' で囲っても良い。
  • パラメタ値が空白等を含まない場合は、パラメタ値を囲む " または ' は省略できる。

以下の変換結果は、コマンドラインで、

msxsl param.xml param.xsl -o param.html param_1=value_1 param_2="value '2'" param3='value "3"'

と指定した時のもの。 ( sample/makefile も参照のこと )

サンプル
XML: sample/param.xml
XSLT: sample/param.xsl
変換結果 (HTML): sample/param.html
[おまけ] サンプル .html 作成用メイクファイル
(last modified : 2004-02-10)

サンプルの変換結果を生成するのに使っているメイクファイル。

実例
sample/makefile
XML
たのしいXML : 僕が実際に XML を使い始めるきっかけになったページ。 基礎はここで学びました。
Extensible Markup Language (XML) 1.1 : W3C 勧告 (2004-02-04)
Extensible Markup Language (XML) 1.0 (Third Edition) : W3C 勧告 (2004-02-04) (errata)
Extensible Markup Language (XML) 1.0 : W3C 勧告 (1998-02-10) (日本語訳)
Namespaces in XML 1.1 : W3C 勧告 (2004-02-04)
Namespaces in XML : W3C 勧告 (1999-01-14) (日本語訳) (errata)
XSLT
XSL Transformations (XSLT) Version 1.0 : W3C 勧告 (1999-11-16) (日本語訳)
XSL Transformations (XSLT) in Mozilla (日本語訳)
XPATH
XML Path Language (XPath) Version 1.0 : W3C 勧告 (1999-11-16) (日本語訳)
その他
RabWiki : XSLT (→ Life with a Rose)
build : 2003-06-04T19:03:23+09:00
lastModified : 2004-10-07T20:03:43+09:00
Atelier RA-rin : (c) 2003,2004 Sagara Takuya