2010-09-02 70 views
18

我想在xsl中有一个键值映射,因此定义了一个具有xml片段的变量,但后来当我尝试访问变量中的xml节点时,出现一个类型错误的xpath xpression无法解析。XSLT:在XSLT中创建映射

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

有一个有点错字对那里发生的,是还你的文档中?它的应该读取。 – Rob 2010-09-02 10:38:07

回答

33

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

嗨, 但是当我做了副本 - 结果树片段打印正确,而不仅仅是那个值 - 只打印结果树中的文本节点。 BR, Keshav – keshav84 2010-09-02 11:48:27

+0

@Keshav:如果你只在变量'$ map'上使用'copy-of' /'value-of'而不尝试使用它作为节点集,它就可以工作。但是,一旦您尝试使用XPath表达式改变结果树片段,它将会失败。 – 2010-09-02 13:03:11

+0

这几乎是*我需要的特殊问题。如果我想使用xpath或$参数而不是硬连线的key-1在地图中查找正确的条目,该怎么办?我已经尝试了但这不起作用。 – gilles27 2012-07-06 16:24:11

5

您可以按工作围绕XSLT 1.0缺少使用变量的内容作为支撑一个节点集。您将不得不依赖分析器制造商添加的扩展。例如,微软已经提供了一个函数来解决此问题:节点集()

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

根据您使用的解析器,上述可能适合您,否则Per T的答案更适合您。

+0

+1对我的回答很好。通常我试图避免供应商特定的扩展,但它是解决它的一种方法! – 2010-09-02 13:04:34

+1

@ Per_T的答案在所有情况下都更好,因为它是一个完全*便携式*解决方案。如果没有'xxx:node-set()'扩展名,这些问题很难解决,但目前的问题不是其中之一。另外,在倡导'xxx:node-set()'解决方案时,应该始终引用'exslt:node-set()',这很便于使用,因为许多供应商提供EXSLT实现。 – 2010-09-02 15:22:37

+0

@Dimitre我必须承认,Per T的答案告诉了我一些关于XSL的事情,我不知道(我不是专家),所以我不知道更好,我肯定是赞成他的伟大答案。 ;)我略微认为,虽然可移植性是一件好事,但它的重要性依赖于上下文,所以我不想考虑我的回答非常糟糕:它可能会很好。 ;)它并没有真正污染你的XSL,因为它不是太侵入。这就是为什么我们对这个解决方案感到高兴,即使我同意你的看法,这并不完美。 :) 感谢您的输入! – Rob 2010-09-02 15:56:32

3

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

所以,如果您的XSLT处理器支持3.0和地图(如撒克逊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>