<xsl:key>
を使用して、または方法2に従って、意図したことを行う方法を次に示します。
サンプル入力ファイル (data.xml):
<?xml version="1.0" encoding="utf-8"?>
<input>
<data>001</data>
<data>002</data>
<data>005</data>
</input>
サンプル マップ ファイル (map.xml):
<?xml version="1.0" encoding="utf-8"?>
<map default="??">
<entry key="001">RZ</entry>
<entry key="002">TH</entry>
<entry key="003">SC</entry>
</map>
サンプル XSL スタイルシート、説明は次のとおりです。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:param name="map-file" select="string('map.xml')" />
<xsl:variable name="map-doc" select="document($map-file)" />
<xsl:variable name="default-value" select="$map-doc/map/@default" />
<xsl:key name="map" match="/map/entry" use="@key" />
<xsl:template match="/input">
<output>
<xsl:apply-templates select="data" />
</output>
</xsl:template>
<xsl:template match="data">
<xsl:variable name="raw-value" select="." />
<xsl:variable name="mapped-value">
<xsl:for-each select="$map-doc">
<xsl:value-of select="key('map', $raw-value)" />
</xsl:for-each>
</xsl:variable>
<data>
<xsl:choose>
<xsl:when test="$mapped-value = ''">
<xsl:value-of select="$default-value" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$mapped-value" />
</xsl:otherwise>
</xsl:choose>
</data>
</xsl:template>
</xsl:stylesheet>
これが行うことは次のとおりです。
- を使用
document()
して開きmap.xml
、結果のノードセットを変数に保存します
- 今後の参考のためにデフォルト値を保存します
<xsl:key>
「マップ」ノード セットに対して動作するように準備します
<xsl:for-each>
ループとしてではなく、key()
関数を呼び出す前に実行コンテキストを切り替える手段として使用します。そうしないkey()
と、「データ」ドキュメントに対して機能し、何も返されません
- 関数で対応するノードを見つけ、
key()
変数に保存します
- 出力の変数値を確認します - 空の場合はデフォルト値を使用します
- 繰り返す(~
<xsl:apply-templates>
)
<xsl:for-each>
この巧妙なトリックの功績は、XSL メーリング リストでこのテクニックを説明したJeni Tennisonの功績によるものです。スレッドを必ずお読みください。
data.xml に対してスタイルシートを実行した場合の出力:
<?xml version="1.0" encoding="utf-8"?>
<output>
<data>RZ</data>
<data>TH</data>
<data>??</data>
</output>
これらはすべて XSLT 1.0 です。XSLT 2.0 が提供する利点を利用した、より優れた、より洗練されたバージョンが存在すると確信していますが、残念ながら、私は XSLT 2.0 にあまり詳しくありません。他の誰かがより良い解決策を投稿しているかもしれません。
編集
コメントの Dimitre Novatchev のヒントにより、かなり短く、より好ましいスタイルシートを作成することができました。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:param name="map-file" select="string('map.xml')" />
<xsl:variable name="map-doc" select="document($map-file)" />
<xsl:variable name="default" select="$map-doc/map/default[1]" />
<xsl:key name="map" match="/map/entry" use="@key" />
<xsl:template match="/input">
<output>
<xsl:apply-templates select="data" />
</output>
</xsl:template>
<xsl:template match="data">
<xsl:variable name="raw-value" select="." />
<data>
<xsl:for-each select="$map-doc">
<xsl:value-of select="(key('map', $raw-value)|$default)[1]" />
</xsl:for-each>
</data>
</xsl:template>
</xsl:stylesheet>
ただし、これを XSLT 1.0 で動作させるには、わずかに異なるマップ ファイルが必要です。
<?xml version="1.0" encoding="utf-8"?>
<map>
<entry key="001">RZ</entry>
<entry key="002">TH</entry>
<entry key="003">SC</entry>
<!-- default entry must be last in document -->
<default>??</default>
</map>