2015-09-07 87 views
2

我是XSLT新手,花了相当多的时间来处理创建内联查找映射,以便将XSLT 2.0中映射列表的另一个值替换为特定值找出我只能用1.0。 :-(XSLT 1.0值查找地图

我的问题是如何能够复制在1.0以下工作XSLT 2.0的代码。我已经尝试了一些事情,但似乎无法得到它的工作。

一点要注意,如果有没有地图则元素应该是空的

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
    </xsl:template> 


<xsl:variable name="mapxml" > 
<map> 
<Country> 
    <input value="GB">RZ</input> 
    <input value="FR">TH</input> 
    </Country> 
</map> 
</xsl:variable> 


    <xsl:variable name="vMap" 
     select="$mapxml" /> 


<xsl:key name="kInputByVal" match="input" 
    use="@value" /> 


    <xsl:template match="Country/text()"> 
     <xsl:sequence select= 
     "(key('kInputByVal', ., $vMap/*/Country)[1]/text() 
      )[1] 
     "/> 

</xsl:template> 
</xsl:stylesheet> 

输入XML:

<user> 
     <Country>GB</Country> 
     <Name>FOO</Name> 
     <Address>BAR</Address> 
<user> 

回答

3

这里是等效XSLT 1.0程序:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:my="http://tempuri.org/dummy" 
    exclude-result-prefixes="my" 
> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*" /> 

    <xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
    </xsl:template> 

    <my:config> 
    <map> 
     <Country> 
     <input value="GB">RZ</input> 
     <input value="FR">TH</input> 
     </Country> 
    </map> 
    </my:config> 
    <xsl:variable name="vCountryMap" select="document('')/*/my:config/map/Country/input" /> 

    <xsl:template match="Country/text()"> 
    <xsl:value-of select="$vCountryMap[@value = current()]" /> 
    </xsl:template> 
</xsl:stylesheet> 

注:

  • 您可以将XSLT内设立额外的节点,只是因为XSLT是XML本身。例如配置数据,就像这里。你只需要确保你为他们使用了不同的命名空间。
  • 命名空间URI必须是唯一的,它们不需要指向现有的文档。像http://tempuri.org/dummy这样的临时URI是完全正确的。
  • <xsl:strip-space elements="*" />指示XSLT处理器忽略输入中无关紧要的空白。这有助于创建整齐缩进的输出。
  • document('')引用了XSLT样式表本身。如果您愿意,也可以将配置保存在额外的XML文件中。
  • exclude-result-prefixes可以防止我们的临时名称空间泄漏到输出。
  • current()指的是XSLT处理器当前正在处理的节点。仅在当前文档中($vCountryMap[@value = .]是行不通的,因为这里的.指的XPath上下文,即<input>节点。)
+0

尼斯XSLT代码和解释,加十.. 。 –

+0

感谢您的快速回答和解释@Tomalak - 这是一种享受,并帮助我理解到底发生了什么:-) –

+1

看看@ michael.hor257k的答案,他也花了很多时间工作的关键。我考虑使用这个任务的关键点矫枉过正,所以我将它从我的解决方案中删除,但当然可以保留它。如果您有非常多的映射和非常大的输入文档(数千个节点的顺序),那么使用密钥会显着提高性能。如果你的投入通常很小,那么它就不会有太大的区别。 – Tomalak

2

密钥在XSLT 1.0工作。为了使用一键从样式表自身查找,您必须使用键之前切换的背景样式表:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:my="http://example.com/my" 
exclude-result-prefixes="my"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="input-by-value" match="input" use="@value" /> 

<my:map> 
    <input value="GB">RZ</input> 
    <input value="FR">TH</input> 
</my:map> 

<!-- identity transform --> 
<xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="Country/text()"> 
    <xsl:variable name="value" select="." /> 
    <!-- switch context to stylesheet in order to use key --> 
    <xsl:for-each select="document('')"> 
     <xsl:value-of select="key('input-by-value', $value)"/> 
    </xsl:for-each> 
</xsl:template> 

</xsl:stylesheet>