XSLT选择非重复节点值

时间:2017-04-14 16:03:31

标签: xml xslt

我试图从列表中获取非重复节点值。我已经尝试过很多建议,但对我来说没什么用。 这是我的源XML

<Records>
  <Record>
    <Files>
      <File>
        <Name>A</Name>
      </File>
      <File>
        <Name>B</Name>
      </File>
      <File>
        <Name>B</Name>
      </File>
    </Files>
  </Record>
  <Record>
    <Files>
      <File>
        <Name>A</Name>
      </File>
      <File>
        <Name>B</Name>
      </File>
      <File>
        <Name>C</Name>
      </File>
      <File>
        <Name>C</Name>
      </File>
    </Files>
  </Record>
</Records>

我正在寻找的输出应该看起来像这样的文本

A,B | A,B,C

第一个逗号分隔集来自第一个记录,第二个集合(“|”之后)来自第二个记录。 (分隔符放置,空格等...不是我的问题,它是删除重复项)

Code I我现在看起来像这样

<xsl:key name="NameId" match="Name" use="." />

<xsl:for-each select="Records/Record">
  <xsl:call-template name="doeach_record"/>
  <xsl:text>|</xsl:text>
</xsl:for-each>

<xsl:template name="doeach_record">
  <xsl:for-each select="Files/File">
    <xsl:if test="generate-id(Name) = generate-id(key('NameId', Name)[1])">
      <xsl:value-of select="Name"/>
    </xsl:if>
    <xsl:text>,</xsl:text>
  </xsl:for-each>
</xsl:template>

它从第一个记录中删除重复项,对于第二个记录,它不选择在第一个记录中找到的名称值。 我得到这样的输出

A,B | ,,C

2 个答案:

答案 0 :(得分:1)

自2007年以来,XSLT 2.0有各种各样的实现,如Saxon 9,XmlPrime,Altova,您可以使用<xsl:template match="Record"><xsl:value-of select="distinct-values(Files/File/Name)" separator=","/></xsl:template>。如果您确实受限于XSLT 1.0,则需要定义一个密钥,该密钥将祖先Record的生成ID与Name一起使用,例如<xsl:key name="unique" match="File/Name" use="concat(generate-id(ancestor::Record), '|', .)"/>,那么您可以使用基于XSLT 1.0密钥的Muenchian分组/不同值方法。

答案 1 :(得分:1)

正如Martin所说,在XSLT 2.0中,distinct-values()是你的朋友。

这是XSLT 2.0略有不同的方法。这包括排序,以防您的输入XML尚未按字母顺序排列。

<xsl:output method="text"/>

<xsl:template match="/">
    <xsl:for-each select="/Records/Record">
        <xsl:for-each select="distinct-values(Files/File/Name)">
            <xsl:sort/>
            <xsl:value-of select="."/>
            <xsl:if test="position() != last()">,</xsl:if>
        </xsl:for-each>
        <xsl:if test="position() != last()"> | </xsl:if>
    </xsl:for-each>
</xsl:template>