使用XSLT选择唯一元素

时间:2010-04-28 09:35:03

标签: xml xslt xpath

我有以下XML:

<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>

3 个答案:

答案 0 :(得分:2)

我建议调查“分组”来解决这个问题。 XSLT 2.0的内置分组功能,如for-each-group,或者,如果您使用的是XSLT 1,则称为“Muenchian Grouping”。

答案 1 :(得分: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()

答案 2 :(得分:0)

你已经得到了很好的答案。在简洁的过程中,我提出了基于Dimitres answer的16行解决方案:

<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分组的XSLT 1.0解决方案(20行):

<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>