XSLT:在XSLT中创建一个Map

时间:2010-09-02 10:16:17

标签: xml xslt map

我希望在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>

3 个答案:

答案 0 :(得分:37)

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()可以检索映射值。 similar question的答案可以在这里使用:。

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

XSLT 1.0 specification

中所述
  

document('')指的是根节点   样式表;那个树   样式表的表示是   与XML完全相同   包含样式表的文档是   最初的源文件。

但是,您不需要使用xsl:variable。您可以直接在xsl:stylesheet下指定您的地图节点,但您必须记住顶级元素必须具有非空名称空间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>

答案 1 :(得分:6)

您可以解决使用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解析器的应用程序(例如:Internet Explorer使用它,以及.NET)。 其他解析器可能有也可能没有这样的扩展(例如,Saxxon,但它的命名略有不同)。但是,它取决于XSLT 2.0,因为它在XSLT 1.0中可以正常工作,而Microsoft尚未在其XML库中支持XSLT 2.0(除非他们最近添加了它)。

根据您使用的解析器,上述内容可能适用于您,否则Per T的答案对您更有帮助。

答案 2 :(得分:5)

在XSLT 3.0工作草案中,提出了一种新的XPath项(map),请参阅maps in XSLT 3.0 WD Spec

因此,如果您的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>