我是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> 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>
…
<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: </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: