问题
I have an XML file that stores movies and their actors.
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="index.xsl"?>
<movies
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="movies.xsd">
<movie movieID="1">
<actors>
<actor actorID="1">
<name link="hello">Bob</name>
</actor>
<actor actorID="2">
<name link="hello">Mike</name>
</actor>
</actors>
</movie>
<movie movieID="2">
<actors>
<actor actorID="1">
<name link="hello">Bob</name>
</actor>
<actor actorID="2">
<name>Daniel</name>
</actor>
</actors>
</movie>
</movies>
As you can see from the code above, I have 2 "movie" elements that contain 2 "actor" child elements each. 3 out of 4 "name" child elements contain an attribute "link": Bob, Mike, Bob
I'm using the following XSLT code to display only the names of the actors that contain an attribute "link":
<xsl:template match="/">
<xsl:text>Actors: </xsl:text>
<xsl:apply-templates select="/movies/movie/actors/actor/name[@link]"/>
</xsl:template>
<xsl:template match="name[@link]">
<xsl:value-of select="." />
<xsl:element name="br" />
</xsl:template>
The output that I get:
Bob
Mike
Bob
As you can see the name "Bob" repeats twice. I want to display only unique actor names that have an attribute "link"
I have tried the following XPath 1.0 queries:
<xsl:template match="[not(@name[@link] = preceding::@name)]">
<xsl:template match="not(@name[@link] = preceding::@name)">
<xsl:template match="not(@name[@link] = preceding-sibling::@name)">
All of them made the page display an error.
回答1:
The efficient way to do grouping like this in XSLT 1.0 is to use Muenchian grouping (I've added a div
and a br
for clarity; feel free to remove them):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="kName" match="actor/name[@link]" use="." />
<xsl:template match="/">
<div>
<xsl:text>Actors: </xsl:text>
<br />
<xsl:variable name="actorNames"
select="/movies/movie/actors/actor/name[@link]"/>
<xsl:apply-templates
select="$actorNames[generate-id() =
generate-id(key('kName', .)[1])]" />
</div>
</xsl:template>
<xsl:template match="name">
<xsl:value-of select="." />
<br />
</xsl:template>
</xsl:stylesheet>
When run on your sample input, this produces:
<div>
Actors: <br />Bob<br />Mike<br />
</div>
来源:https://stackoverflow.com/questions/15455618/select-unique-element-values-based-on-the-attribute-with-xpath-1-0