web-dev-qa-db-ja.com

XSLT:XSLTでのマップの作成

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>
22
keshav84

XSLT 2.0

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

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>
_
40
Per T

変数の内容をノードセットとして使用するためのサポートが欠けている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の回答の方が適しています。

7
Rob

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> 
5
j_maly