2015-09-07 71 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>