我是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 ......次出现(第1次可以跳过)。 我知道这是因为关键功能之后的“[2]”。我找到的大多数例子都是关于如何删除重复项,在这里我需要相反,所以这就是我发现给我(接近)我需要的技巧。可能有更好的方法来实现这一目标......
感谢任何帮助。
谢谢, 布鲁诺
答案 0 :(得分: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> Players: </xsl:text>
<xsl:apply-templates select="$vDups" mode="copy"/>
<xsl:text> </xsl:text>
</xsl:if>
</xsl:template>
<xsl:template match="player" mode="copy">
<xsl:if test="position() > 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.
答案 1 :(得分:1)
您也可以通过以下方式实现这一目标:
<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: </xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="team">
<xsl:text> </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: