2010-04-28 77 views
4

独特的元素我有下面的XML:选择使用XSLT

<option> 
    <title>ABC</title> 
    <desc>123</desc> 
</option> 
<option> 
    <title>ABC</title> 
    <desc>12345</desc> 
</option> 
<option> 
    <title>ABC</title> 
    <desc>123</desc> 
</option> 
<option> 
    <title>EFG</title> 
    <desc>123</desc> 
</option> 
<option> 
    <title>EFG</title> 
    <desc>456</desc> 
</option> 

使用XSLT,我想将其改造成:

<choice> 
    <title>ABC</title> 
    <desc>123</desc> 
    <desc>12345</desc> 
</choice> 
<choice> 
    <title>EFG</title> 
    <desc>123</desc> 
    <desc>456</desc> 
</choice> 
+0

很好的问题(1)。查看我的答案,了解最低(19行)XSLT 2.0解决方案。 :) – 2010-04-28 13:12:54

回答

2

我会建议寻找到“分组”来解决这个问题。无论是XSLT 2.0的内置分组函数,就像for-each-group一样,或者如果您使用的是XSLT 1,则称为“Muenchian分组”。

+0

这已经解决了我已经有3小时的问题,谢谢堆,因为每个小组都工作得很好。 – 2010-04-28 12:37:32

+0

+1好答案。 – markusk 2010-04-29 06:17:43

1

这里是一个最小的XSLT 2.0解决方案

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/*"> 
    <choices> 
    <xsl:for-each-group select="*/title" group-by="."> 
    <choice> 
     <title> 
     <xsl:sequence select="current-grouping-key()"/> 
     </title> 
     <xsl:for-each-group select="current-group()/../desc" group-by="."> 
     <xsl:sequence select="."/> 
     </xsl:for-each-group> 
    </choice> 
    </xsl:for-each-group> 
    </choices> 
</xsl:template> 
</xsl:stylesheet> 

请注意使用的功能current-group()current-grouping-key()

+0

+1好答案。 – markusk 2010-04-29 06:17:07

+0

@Dimitre,你可否详细说一下'',它有什么用?我从来没有用过它,从来没有觉得我失去了一些东西,但也许使用它可以节省我一些麻烦? – topskip 2010-04-29 06:44:38

+0

@Patrick:''类似于'',但它不会创建在其“select”属性中选择的节点的副本。相反,它产生了像这些节点的“引用”。总而言之,''比''更经济有效, – 2010-04-29 12:42:55

0

你已经得到了很好的答案。在简洁的追逐,我提出我的16号线的解决方案,基于Dimitres answer

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

    <xsl:template match="/*"> 
    <choices> 
     <xsl:for-each-group select="option" group-by="title"> 
     <choice> 
      <xsl:sequence select="title"/> 
      <xsl:for-each-group select="current-group()/desc" group-by="."> 
      <xsl:sequence select="."/> 
      </xsl:for-each-group> 
     </choice> 
     </xsl:for-each-group> 
    </choices> 
    </xsl:template> 
</xsl:stylesheet> 

注意里面for-each-group当前上下文节点是当前组中的第一项,而current-group()返回的所有项目的列表当前组。我利用title元素对于输入和输出是相同的事实,并复制每个组的第一个标题。

并且为了完整性,使用Muenchian分组的(20线)的XSLT 1.0溶液:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

    <xsl:key name="title" match="option/title" use="."/> 
    <xsl:key name="desc" match="option/desc" use="."/> 

    <xsl:template match="/*"> 
    <choices> 
     <xsl:for-each select="option/title[count(.|key('title',.)[1]) = 1]"> 
     <choice> 
      <xsl:copy-of select="."/> 
      <xsl:for-each select="key('title',.)/../desc 
       [count(.|key('desc', .)[../title=current()][1]) = 1]"> 
      <xsl:copy-of select="."/> 
      </xsl:for-each> 
     </choice> 
     </xsl:for-each> 
    </choices> 
    </xsl:template> 
</xsl:stylesheet>