开发者

XSLT : Creating a Map in XSLT

I want to have a key value map in xsl and so defined a variable which has an xml fragment, but later when I try to access the xml nodes in the variable I get an error that type of the xpath 开发者_运维技巧xpression cannot be resolved.

<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

Using XSLT 2.0, the following solution works:

  <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

You cannot use a result tree fragment in a XPath expression in XSLT 1.0, but fn:document() can retrieve map values. An answer to a similar question will work here:.

<xsl:value-of select="document('')//xsl:variable[@name='map']/map/entry[@key='key-1']"/>

As described in the XSLT 1.0 specification:

document('') refers to the root node of the stylesheet; the tree representation of the stylesheet is exactly the same as if the XML document containing the stylesheet was the initial source document.

However, you don't need to use xsl:variable for this. You could specify your map node directly under xsl:stylesheet, but you must remember that a top level elements must have a non null namespace 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>


You can sort of work around XSLT 1.0 missing support for using the variable's contents as a node set. You'll have to rely on extensions added by the parser's maker. For example, Microsoft has offered a function to work around this: node-set()

Your XSL will look like this:

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

Notice the namespace and the msxsl-prefix here. This will only work in applications based on Microsoft's parser (for example: Internet Explorer utilizes it, as well as .NET). Other parsers may or may not have such an extension (Saxxon does, for example, but it's named a bit differently). But, it eliminates depending on XSLT 2.0, as this will work fine in XSLT 1.0 and Microsoft has yet to support XSLT 2.0 in their XML library (unless they've added it recently).

Depending on the parser you're using, the above may work fine for you, otherwise Per T's answer is better for you.


In XSLT 3.0 Working Draft, a new kind of XPath item (map) is proposed, see maps in XSLT 3.0 WD Spec.

So, if your XSLT processor supports 3.0 and maps (e.g. Saxon 9.4), you can use the following code:

<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> 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜