2010-09-22 74 views
2

什麼是XSLT 2.0樣式表,將改變XSLT樣式表:合併的元素爲一個

<paramList> 
    <param name="y" out="true"/> 
    <param name="y" in="true"/> 
    <param name="z" out="true"/> 
    <param name="x" in="true"/> 
</paramList> 

<paramList> 
    <param name="x" in="true" /> 
    <param name="y" in="true" out="true"/> 
    <param name="z" out="true"/> 
</paramList> 

在結果中, 「在,只有」 參數之前 「在&出」參數,這反過來又在「僅輸出」參數之前。此外,這兩個「y」元素已合併爲一個。

+0

您有沒有機會使用XSLT 2.0? – 2010-09-22 14:29:49

+0

是的,使用XSLT 2.0。 – JaysonFix 2010-09-22 14:31:48

+0

好問題(+1)。看到我的答案,對已經發布的解決方案的代碼進行了小幅改進。 – 2010-09-22 16:09:30

回答

0
<?xml version="1.0" ?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:template match="/paramList"> 
    <xsl:copy> 
    <xsl:for-each-group select="param" group-by="@name"> 
     <xsl:sort select="current-group()/@in" order="descending"/> 
     <xsl:sort select="current-group()/@out"/> 
     <param name="{current-grouping-key()}"> 
     <xsl:for-each select="current-group()/@*"> 
      <xsl:copy/> 
     </xsl:for-each> 
     </param> 
    </xsl:for-each-group> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 
+0

非常感謝,尼克!它爲我工作得很好。 – JaysonFix 2010-09-22 14:52:15

+0

你爲什麼關心按名稱排序屬性?Compact Code:< xsl:for-each-group>' – 2010-09-22 15:24:11

+0

@Alejandro:排序依據是否存在輸入/輸出屬性,來自問題: 結果中,「in,only」參數位於「in&out」參數之前,反過來,在「僅輸出」參數之前。此外,這兩個「y」元素已合併爲一個。 – 2010-09-22 15:34:53

0

以防萬一有人需要做的XSLT 1:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" 
> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:key name="paramsByName" match="param" use="@name"/> 
    <xsl:template match="/paramList"> 
     <xsl:copy> 
      <xsl:for-each select="param[count(. | key('paramsByName', @name)[1]) = 1]"> 
      <xsl:sort select="@name"/> 
      <xsl:copy> 
       <xsl:for-each select="key('paramsByName', @name)"> 
       <xsl:copy-of select="@*"/> 
      </xsl:for-each> 
      </xsl:copy> 
     </xsl:for-each> 
    </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

它使用Munchian grouping作爲XSLT 1不具備分組構造。

編輯:

這顯然還可以對進出的屬性只是複製在這種情況下,下面的樣式表不工作(也是繼Dimetre的建議:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" 
> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:key name="paramsByName" match="param" use="@name"/> 
    <xsl:template match="/paramList"> 
     <xsl:copy> 
      <xsl:for-each select="param[count(. | key('paramsByName', @name)[1]) = 1]"> 
      <xsl:sort select="@name"/> 
      <xsl:copy-of select="key('paramsByName', @name)/@*[local-name() = 'in' or local-name() = 'out']"/> 
     </xsl:for-each> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 
+0

正如@Nick Jones指出的那樣,OP需要這樣的命令:只有@in,@in和@out,只有@out。另外,你不需要最內層的'for-each'。您可以使用'fn:key()'作爲第一步。 – 2010-09-22 16:53:09

+0

請注意,「paramsByName」鍵將應用於文檔的所有「param」節點,如果輸入文檔具有多個「paramList」,且該參數具有相同名稱的「param」,則此解決方案可能無法正常工作。 – dolmen 2010-09-27 09:58:13

0

小改進:

在@ Nick-Jones'和@Obalix的解決方案中,它的編寫較短

<xsl:copy-of select="current-group()/@*"/> 

分別或

<xsl:copy-of select="key('paramsByName', @name)/@*"/> 

比,:

<xsl:for-each select="current-group()/@*"> 
    <xsl:copy/> 
</xsl:for-each> 

<xsl:for-each select="key('paramsByName', @name)">  
<xsl:copy-of select="@*"/>  
</xsl:for-each>  
0

在輸入文檔中有多個paramList元素的情況下,Obalix的答案可能不起作用。如果文檔描述了一個軟件界面,其中有多個過程,每個過程都有一個paramList,我認爲這可能會使海報感興趣。

下面是一個簡單的輸入:

<root> 
    <func name="one"> 
    <paramList> 
     <param name="y" out="true"/> 
     <param name="y" in="true"/> 
     <param name="z" out="true"/> 
     <param name="x" in="true"/> 
    </paramList> 
    </func> 

    <func name="two"> 
    <paramList> 
     <param name="z" in="true"/> 
    </paramList> 
    </func> 
</root> 

這是我提出的樣式表,建立在Obalix的答案。訣竅是使用包含paramList元素的ID的本地密鑰ID。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" 
> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:key name="paramsByName" match="param" use="concat(generate-id(..), '/', @name)"/> 
    <xsl:template match="paramList"> 
    <xsl:copy> 
     <xsl:variable name="id" select="generate-id(.)"/> 
     <xsl:for-each select="param[count(. | key('paramsByName', concat($id, '/', @name))[1]) = 1]"> 
     <xsl:copy> 
      <xsl:copy-of select="key('paramsByName', concat($id, '/', @name))/@*"/> 
     </xsl:copy> 
     </xsl:for-each> 
    </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 
+0

沒有像一般解決方案那樣的東西。使用XSLT,我們將具有衆所周知的模式的輸入綁定到具有衆所周知的模式的輸出。所以,如果你要改變輸入模式,你需要一個不同的樣式表。 – 2010-09-27 14:14:50

+0

@Alejandro:我不是在提出一個通用的解決方案。海報在某種情況下有問題。 XML標籤對編寫架構的XML標籤有意義,我試圖理解如何使用問題的XML片段。其他人提出的一般性答案可能會帶來一些問題。 XSLT中的鍵很難理解,並且解釋了他們的陷阱。 – dolmen 2010-09-27 23:27:13

+2

你寫了*「在有多個paramList元素的情況下,Obalix的答案可能不起作用」*呃......即使接受的答案也不會在模式中發生這種變化。這就是我的意思*「沒有像通用解決方案這樣的東西」*聲明。大部分對輸入模式的改變都需要在樣式表中進行更改。 – 2010-09-27 23:56:55

相關問題