2011-02-02 443 views
1

我是新來的xslt,我擔心這個問題取決於我掛在程序的思維。合併和重命名字段在xslt

我有一組信息,我想要重命名,並且在某些情況下可以進行濃縮。我可以處理重命名,但凝結讓我失望。我的做法是重命名所有內容,然後,如果重命名時出現重複,則刪除重複項。爲了清楚起見,這裏有一些代碼。

輸入:

<variables> 
    <var value="a-value"> a </var> 
    <var value="b-value"> b </var> 
    <var value="c-value"> c </var> 
    <var value="d-value"> d </var> 
</variables> 

所需的輸出:

<variables> 
    <var value="new-a-value"> new-a </var> 
    <var value="new-b-and-c-value"> new-b-and-c </var> 
    <var value="new-d-value"> new-d </var> 
</variables> 

我的XSLT:

<xsl:for-each select="var"> 
    <xsl:choose> 

     <xsl:when test="@value = 'a-value'"> 
     <var value="new-a-value"> new-a </var> 
     </xsl:when> 

     <xsl:when test="@value = 'b-value'"> 
     <var value="new-b-and-c-value"> new-b-and-c </var> 
     </xsl:when> 

     <xsl:when test="@value = 'c-value'"> 
     <var value="new-b-and-c-value"> new-b-and-c </var> 
     </xsl:when> 

     <xsl:when test="@value = 'd-value'"> 
     <var value="new-d-value"> new-d </var> 
     </xsl:when> 

    </xsl:choose> 
    </xsl:for-each> 

我想改名後刪除重複項。我不確定該從哪裏出發。我的直覺促使我想設置某種檢查方式來檢查何時發現b值或c值或通過中間處理的xml執行另一次迭代,以移除重複項,但我認爲這兩種方法都不是在xslt中可行。

回答

1

關於「通過中間處理的xml執行另一個迭代來移除重複項」 - 這可以在XSLT 2.0中實現,或者您在XSLT 1.0中具有節點集擴展。但我認爲在這種情況下是不必要的。

,而不是一個,每一個選擇 - 當 - 測試 - 否則,不用申請模板:

<xsl:apply-templates select="var" /> 

然後,你必須對你要處理每種類型變種的模板,大致相當於您的xsl:當元素:

<xsl:template match="var[@value = 'a-value']"> 
    <var value="new-a-value"> new-a </var> 
</xsl:template> 

而對於b/C項目,是這樣的:

<xsl:template match="var[@value = 'b-value' or @value = 'c-value'][1]"> 
    <var value="new-b-and-c-value"> new-b-and-c </var> 
</xsl:template> 

[1]使模板僅在其兄弟中的第一個此類var時觸發。這是否正是你想要的,取決於你的輸入結構可能會有所不同。 但給你的示例輸入,它的工作原理。您還需要一個模板來處理B或C瓦爾不在第一:

<xsl:template match="var[@value = 'b-value' or @value = 'c-value']" 
     priority="-1" /> 

注意空體;和低優先級,所以那個的b/c變量首先不會被這個模板處理。

綜上,鑑於你的樣品輸入,下面的XSLT樣式表使你的要求的輸出:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="/variables"> 
     <xsl:copy> 
     <xsl:apply-templates select="var"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="var[@value = 'a-value']"> 
     <var value="new-a-value"> new-a </var> 
    </xsl:template> 

    <xsl:template match="var[@value = 'b-value' or @value = 'c-value'][1]"> 
     <var value="new-b-and-c-value"> new-b-and-c </var> 
    </xsl:template> 

    <xsl:template match="var[@value = 'b-value' or @value = 'c-value']" 
     priority="-1" /> 

    <xsl:template match="var[@value = 'd-value']"> 
     <var value="new-d-value"> new-d </var> 
    </xsl:template> 
</xsl:stylesheet> 

如果不知何故不符合你腦子裏的東西,讓我知道,我們可以遍歷。

如果您知道輸入中只有一個'b',您可以變得更簡單,只需要一個模板來匹配'b'並用新值替換;並有一個空模板來匹配'c'並將其扔掉。但它聽起來像也許你不能做出這樣的假設......

+0

+1很好的回答。我會給予更高的優先權,而不是負面的。 – 2011-02-02 23:08:09

+0

@Alej:你會給予'[1]`模板更高的優先權,對吧?而不是空模板的負面優先。起初我以爲你的意思是你會在同一個模板上將負面的優先權更改爲更高的優先權。 – LarsH 2011-02-03 02:03:03

3

重構:使更簡單,真正的問題變得清晰:對映射的鍵值進行分組。

這個樣式表:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:v="value" 
exclude-result-prefixes="v"> 
    <xsl:key name="kVarByReplace" 
      match="var" 
      use="document('')/*/v:v[@o=current()/@value]/@n"/> 
    <v:v o="a-value" n="new-a-value"/> 
    <v:v o="b-value" n="new-b-and-c-value"/> 
    <v:v o="c-value" n="new-b-and-c-value"/> 
    <v:v o="d-value" n="new-d-value"/> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="var"> 
     <xsl:variable name="vKey" 
         select="document('')/*/v:v[@o=current()/@value]/@n"/> 
     <xsl:if test="count(.|key('kVarByReplace',$vKey)[1]) = 1"> 
      <var value="{$vKey}"> 
       <xsl:value-of select="$vKey"/> 
      </var> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

輸出:

<variables> 
    <var value="new-a-value">new-a-value</var> 
    <var value="new-b-and-c-value">new-b-and-c-value</var> 
    <var value="new-d-value">new-d-value</var> 
</variables> 

注意:在xsl:key/@use使用document()功能。

這表明多麼容易,這將是在XSLT 2.0:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:variable name="vMap" as="element()*"> 
     <v o="a-value">new-a-value</v> 
     <v o="b-value">new-b-and-c-value</v> 
     <v o="c-value">new-b-and-c-value</v> 
     <v o="d-value">new-d-value</v> 
    </xsl:variable> 
    <xsl:template match="variables"> 
     <variables> 
      <xsl:for-each-group select="var" 
           group-by="$vMap[@o=current()/@value]"> 
       <var value="{current-grouping-key()}"> 
        <xsl:value-of select="current-grouping-key()"/> 
       </var> 
      </xsl:for-each-group> 
     </variables> 
    </xsl:template> 
</xsl:stylesheet> 

用鑰匙也爲地圖首選解決方案。

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:v="value" 
exclude-result-prefixes="v"> 
    <xsl:key name="kValByOld" match="v:v" use="@o"/> 
    <xsl:key name="kVarByReplace" 
      match="var" 
      use="document('')/*/v:v[@o=current()/@value]/@n"/> 
    <xsl:variable name="vStylesheet" select="document('')"/> 
    <v:v o="a-value" n="new-a-value"/> 
    <v:v o="b-value" n="new-b-and-c-value"/> 
    <v:v o="c-value" n="new-b-and-c-value"/> 
    <v:v o="d-value" n="new-d-value"/> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="var"> 
     <xsl:variable name="vOld" select="@value"/> 
     <xsl:for-each select="$vStylesheet"> 
      <xsl:variable name="vNew" 
          select="key('kValByOld',$vOld)/@n"/> 
      <xsl:for-each select="$vOld"> 
       <xsl:if test="count(..|key('kVarByReplace',$vNew)[1])=1"> 
        <var value="{$vNew}"> 
         <xsl:value-of select="$vNew"/> 
        </var> 
       </xsl:if> 
      </xsl:for-each> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 
2

這是一個XSLT 2.0樣式表,它可以從輸入中生成所需的輸出。無論是做正確的事與其他輸入是另外一個問題,但它的設計是適當擴展,並展示了多種技術,可以用於這樣的問題:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:f="http://local-functions/" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
exclude-result-prefixes="f xs"> 

<xsl:output indent="yes"/> 

<xsl:template match="variables"> 
    <variable> 
    <xsl:for-each-group select="*" group-adjacent="f:is-groupable(.)"> 
     <xsl:choose> 
      <xsl:when test="f:is-groupable(.)"> 
       <var value="new-{string-join(current-group()/replace(@value, '-value', ''), '-and-')}-value"> 
       <xsl:text> new-</xsl:text> 
       <xsl:value-of select="string-join(current-group()/normalize-space(.), '-and-')"/> 
       <xsl:text> </xsl:text> 
       </var> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:for-each select="current-group()"> 
       <var value="new-{@value}"> 
        <xsl:value-of select="replace(., '\S+', 'new-$0')"/> 
       </var> 
       </xsl:for-each>  
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:for-each-group> 
    </variable> 
</xsl:template> 

<xsl:function name="f:is-groupable" as="xs:boolean"> 
    <xsl:param name="var" as="element(var)"/> 
    <xsl:sequence select="$var/@value = ('b-value', 'c-value')"/> 
</xsl:function>  

</xsl:stylesheet>