XSLT:查找每个子节点中的重复项



我是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、3、4…出现(第一个可以跳过)。我知道这是因为键函数后的"[2]"。我发现的大多数例子都是关于如何删除重复,这里我需要的是相反的,所以这是我发现给我(接近)我需要的技巧。也许有更好的方法来实现这一点…

任何帮助都是感激的。

谢谢,布鲁诺

你做对了!需要的主要更改是对键的调整-特别是需要考虑@lastname关于父<team>元素的唯一信息:

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

要做的另一个更改是您已经注意到的:您需要[2]谓词以外的东西来获得所有重复项。诀窍是在@match属性中使用相同的键,以便选择所有其他元素:

key(
  'kPlayerByLastnameAndTeam',
  concat(parent::team/@name, '+', @lastname))
[not(generate-id() = generate-id(current()))]

要查看所有这些操作,请查看完整的解决方案

当这个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>
输出:

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

相关内容

  • 没有找到相关文章

最新更新