Xslにキー値マップを設定し、xmlフラグメントを持つ変数を定義したいのですが、後で変数のxmlノードにアクセスしようとすると、xpath xpressionのタイプを解決できないというエラーが発生します。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="map">
<map>
<entry key="key-1">value1</entry>
<entry key="key-2">value2</entry>
<entry key="key-3">value3</entry>
</map>
</xsl:variable>
<output>
<xsl:value-of select="$map/entry[@key='key-1']"/>
</output>
</xsl:template>
</xsl:stylesheet>
XSLT 2.0を使用すると、次のソリューションが機能します。
_ <xsl:variable name="map">
<entry key="key-1">value1</entry>
<entry key="key-2">value2</entry>
<entry key="key-3">value3</entry>
</xsl:variable>
<xsl:template match="/">
<output>
<xsl:value-of select="$map/entry[@key='key-1']"/>
</output>
</xsl:template>
_
XSLT 1.0のXPath式で結果ツリーフラグメントを使用することはできませんが、fn:document()
はマップ値を取得できます。 同様の質問 への回答はここで機能します。
_<xsl:value-of select="document('')//xsl:variable[@name='map']/map/entry[@key='key-1']"/>
_
XSLT 1.0仕様 で説明されているように:
document('')
は、スタイルシートのルートノードを参照します。スタイルシートのツリー表現は、スタイルシートを含むXMLドキュメントが最初のソースドキュメントである場合とまったく同じです。
ただし、これには_xsl:variable
_を使用する必要はありません。 _xsl:stylesheet
_のすぐ下にマップノードを指定することもできますが、最上位の要素にはnull以外の名前空間URIが必要であることを覚えておく必要があります。
_<xsl:stylesheet
version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="some.uri" exclude-result-prefixes="my">
<my:map>
<entry key="key-1">value1</entry>
<entry key="key-2">value2</entry>
<entry key="key-3">value3</entry>
</my:map>
<xsl:template match="/">
<output>
<xsl:value-of select="document('')/*/my:map/entry[@key='key-1']"/>
</output>
</xsl:template>
</xsl:stylesheet>
_
変数の内容をノードセットとして使用するためのサポートが欠けているXSLT 1.0を回避するための一種の作業を行うことができます。パーサーのメーカーによって追加された拡張機能に依存する必要があります。たとえば、Microsoftはこれを回避する関数を提供しています:node-set()
XSLは次のようになります。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-Microsoft-com:xslt">
<xsl:template match="/">
<xsl:variable name="map">
<map>
<entry key="key-1">value1</entry>
<entry key="key-2">value2</entry>
<entry key="key-3">value3</entry>
</map>
</xsl:variable>
<output>
<xsl:value-of select="msxsl:node-set($map)/map/entry[@key='key-1']"/>
</output>
</xsl:template>
</xsl:stylesheet>
名前空間とmsxsl-prefixに注意してください。これは、Microsoftのパーサーに基づくアプリケーションでのみ機能します(たとえば、.NETだけでなくInternet Explorerでも使用されます)。他のパーサーにはそのような拡張機能がある場合とない場合があります(たとえば、Saxxonにはありますが、名前が少し異なります)。ただし、これはXSLT 2.0に依存しなくなります。これはXSLT 1.0で正常に機能し、MicrosoftはまだXMLライブラリでXSLT 2.0をサポートしていないためです(最近追加した場合を除く)。
使用しているパーサーによっては、上記がうまく機能する場合があります。そうでない場合は、Per Tの回答の方が適しています。
XSLT 3.0ワーキングドラフトでは、新しい種類のXPathアイテム(マップ)が提案されています。XSLT3.0 WD仕様の マップを参照してください 。
そのため、XSLTプロセッサが3.0とマップ(Saxon 9.4など)をサポートしている場合は、次のコードを使用できます。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="3.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<xsl:variable name="map" select="
map {
'key-1' := 'value1',
'key-2' := 'value2',
'key-3' := 'value3' }">
</xsl:variable>
<output>
<xsl:value-of select="
$map('key-1') || ', ' || $map('key-2') || ', ' || $map('key-3')"/>
</output>
</xsl:template>
</xsl:stylesheet>