2010-09-22 73 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

相关问题