Xml XSLT:在每个子级中查找重复项

Xml XSLT:在每个子级中查找重复项,xml,xslt,duplicates,xslt-1.0,Xml,Xslt,Duplicates,Xslt 1.0,我是XSLT/XML新手 我有一个类似以下内容的XML文件: <event> <division name="Div1"> <team name="Team1"> <player firstname="A" lastname="F" /> <player firstname="B" lastname="G" /> <player firstname="C" lastname="H"

我是XSLT/XML新手

我有一个类似以下内容的XML文件:

<event>
  <division name="Div1">
    <team name="Team1">
      <player firstname="A" lastname="F" />
      <player firstname="B" lastname="G" />
      <player firstname="C" lastname="H" />
      <player firstname="D" lastname="G" />
    </team>
    <team name="Team2">
      <player firstname="A" lastname="F" />
      <player firstname="B" lastname="G" />
      <player firstname="C" lastname="H" />
      <player firstname="D" lastname="I" />
    </team>
  </division>
</event>

我正在尝试编写一个XSL转换(与xsltproc一起使用),以提供同一团队中姓氏相同的玩家的姓名

在四处搜索后,我得出以下结论:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="text" encoding="UTF-8"/>

  <xsl:key name="lastnames" match="player" use="@lastname" />

  <xsl:template match="/">    
    <xsl:for-each select="event/division/team">

      <xsl:variable name="dups" select="player[generate-id() = generate-id(key('lastnames', @lastname)[2])]" />

      <xsl:if test="$dups">
        Team: <xsl:value-of select="@name" /> (<xsl:value-of select="../@name" />)
        Players: 
        <xsl:for-each select="$dups">
          <xsl:value-of select="@lastname" />, <xsl:value-of select="@firstname" />.
        </xsl:for-each>
      </xsl:if>

    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

小组:()
玩家:
, .
主要的问题是它给了我所有球队所有球员的副本,而不仅仅是每个球队

在上面的例子中,它应该只返回一个事件(对于Team1中的玩家D G)

小问题:这只打印第二次出现的副本。最好它应该打印第二,第三,第四。。。事件(可以跳过第一个)。 我知道这是因为键函数后面有“[2]”。我发现的大多数例子都是关于如何删除重复项的,这里我需要相反的方法,所以这是我发现的一个技巧,可以提供(接近)我需要的东西。也许有更好的方法来实现这一点

感谢您的帮助

谢谢,
布鲁诺

你走对了路!所需的主要更改是对键的调整,尤其是需要考虑
@lastname
值和有关父
元素的唯一信息:

<xsl:key
  name="kPlayerByLastnameAndTeam"
  match="player"
  use="concat(parent::team/@name, '+', @lastname)" />
要看到所有这些都在起作用,请看一下这个完整的解决方案

当此XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output omit-xml-declaration="yes" indent="yes" method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:key
    name="kPlayerByLastnameAndTeam"
    match="player"
    use="concat(../@name, '+', @lastname)"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="team">
    <xsl:apply-templates
      select="*[
                generate-id() =
                generate-id(key(
                  'kPlayerByLastnameAndTeam',
                  concat(../@name, '+', @lastname))[1])
               ]"/>
  </xsl:template>

  <xsl:template match="player">
    <xsl:variable
      name="vDups"
      select="key(
                'kPlayerByLastnameAndTeam',
                concat(../@name, '+', @lastname))
              [not(generate-id() = generate-id(current()))]"/>
    <xsl:if test="$vDups">
      <xsl:value-of
        select="concat('Team: ', ../@name, ' (', ../../@name, ')')"/>
      <xsl:text>&#10;Players: </xsl:text>
      <xsl:apply-templates select="$vDups" mode="copy"/>
      <xsl:text>&#10;&#10;</xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="player" mode="copy">
    <xsl:if test="position() &gt; 1">; </xsl:if>
    <xsl:value-of select="concat(@lastname, ', ', @firstname, '.')"/>
  </xsl:template>

</xsl:stylesheet>
<event>
  <division name="Div1">
    <team name="Team1">
      <player firstname="A" lastname="F"/>
      <player firstname="B" lastname="G"/>
      <player firstname="C" lastname="H"/>
      <player firstname="D" lastname="G"/>
    </team>
    <team name="Team2">
      <player firstname="A" lastname="F"/>
      <player firstname="B" lastname="G"/>
      <player firstname="C" lastname="H"/>
      <player firstname="D" lastname="I"/>
    </team>
  </division>
</event>
Team: Team1 (Div1)
Players: G, D.

您还可以通过以下方式实现此目的:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="text" encoding="UTF-8"/>
  <xsl:strip-space elements="*"/>
  <xsl:key name="lastnames" match="player" use="@lastname"/>

  <xsl:template match="event">
    <xsl:text>Team:&#10;</xsl:text>
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="team">
    <xsl:text>&#10;</xsl:text>
    <xsl:value-of select="concat(@name,' (',parent::division/@name,')')"/>
    <xsl:text> Players: </xsl:text>
    <xsl:for-each select="player[@lastname = preceding-sibling::player/@lastname]">
      <xsl:value-of select="concat(@lastname,', ', @firstname,'.')"/>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

谢谢你们两位的建议。它现在工作正常:-)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="text" encoding="UTF-8"/>
  <xsl:strip-space elements="*"/>
  <xsl:key name="lastnames" match="player" use="@lastname"/>

  <xsl:template match="event">
    <xsl:text>Team:&#10;</xsl:text>
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="team">
    <xsl:text>&#10;</xsl:text>
    <xsl:value-of select="concat(@name,' (',parent::division/@name,')')"/>
    <xsl:text> Players: </xsl:text>
    <xsl:for-each select="player[@lastname = preceding-sibling::player/@lastname]">
      <xsl:value-of select="concat(@lastname,', ', @firstname,'.')"/>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>
Team:

Team1 (Div1) Players: G, D.
Team2 (Div1) Players: