XSLT:在每个孩子中找到重复项 [英] XSLT: find duplicates within each child

查看:124
本文介绍了XSLT:在每个孩子中找到重复项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是XSLT / XML的新手。

I'm new to XSLT/XML.

我有一个与此类似的XML文件:

I have an XML file similar to this:

<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一起使用)给我的名字

I'm trying to write a XSL Transformation (to use with xsltproc) to give me the names of players with the same lastname within the same team.

搜索结果后,我想到了:

After searching around I came up to this:

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

主要的问题是它给了我所有团队的所有玩家重复,不只是在每个团队中。

The main problem with this is that it's giving me duplicates across all the players of all teams, not just within each team.

在上面的例子中,它应该只返回一次(对于Team1中的球员DG)。

In the above example it should return only one occurrence (for player D G in Team1).

次要问题:这仅打印第二次出现的副本。最好打印第2,第3,第4 ...出现(第1个可以跳过)。
我知道这是因为[2]之后的关键功能。我发现的大多数例子是关于如何清除重复,在这里我需要相反的,所以这是我发现给我(接近)我需要的技巧。可能有更好的方式实现这一点...

Minor problem: this prints only the 2nd occurrence of a duplicate. Preferably it should print 2nd, 3rd, 4th... occurrences (the 1st can be skipped). I know this is because of the "[2]" after the key function. Most examples I found were on how to remove duplicates, here I need the opposite, so this was the trick I found to give me (close to) what I need. Probably there are better ways of achieving this...

任何帮助都不胜感激。

谢谢,
布鲁诺

Thanks, Bruno

推荐答案

你在正确的轨道上!所需的主要变化是调整关键 - 特别是需要考虑 @lastname 关于父级的唯一信息< team> 元素:

You're on the right track! The primary change needed is an adjustment to the key - it particular, in needs to take into account the @lastname value and unique information about the parent <team> element:

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

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

The other change to make is one you've already noted: you need something other than a [2] predicate to get all duplicates. The trick to that is to use the same key in a @match attribute such that all other elements are selected:

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

要查看所有这一切,请查看这个完整的解决方案。

To see all this in action, take a look at this complete solution.

当这个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>

...针对提供的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>

...想要的结果生成:

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

这篇关于XSLT:在每个孩子中找到重复项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆