Question

Given the following xml document...

   <ws>
       <series year="2005" mvp="Jermaine Dye">
          <team name="Chicago White Sox" wins="4" />
          <team name="Houston Astros" wins="0" />
       </series>
       <series year="2004" mvp="Manny Ramirez">
          <team name="Boston Red Sox" wins="4" />
          <team name="St. Louis Cardinals" wins="0" />
       </series>
    </ws>

I have created a key to get the name attribute of the first team in each series, and I am trying to loop through and list out each name for each series as follows; I am currently not returning any results and am not sure what is wrong with my value-of reference?...

<xsl:key name="winners" match="team[1]" use="@name" />

    <xsl:template match="/">
        <xsl:for-each select="ws/series">
             <xsl:value-of select="key('winners', @name)" />
        </xsl:for-each>
    </xsl:template>

Expected output would be...

Chicago White Sox (the first team from series 1)
Boston Red Sox (the first team from series 2)

The xml data I have provided only includes 2 series elements when in actuality there are hundred's. The key is used to speed up the transformation process and works along with other keys to generate my result document.

Was it helpful?

Solution

I am trying to list out the name of the first team in each series

Using a key is an unnecessary complication for such a simple task. Try simply:

<xsl:template match="/">
    <xsl:for-each select="ws/series">
        <xsl:value-of select="team[1]/@name" />
    </xsl:for-each>
</xsl:template>

Of course, you will want to add some kind of wrapper or separator to this, otherwise you'll just get a jumble of all names - say (assuming the output method is text):

<xsl:template match="/">
    <xsl:for-each select="ws/series">
        <xsl:value-of select="team[1]/@name" />
        <xsl:if test="position()!=last()">
            <xsl:text>&#10;</xsl:text>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

EDIT:

To do this (artificially) using a key, you must ask yourself what is connecting a team to its series (other than being a child thereof). The answer here is 'nothing'. However, a team has access to its parent series data. Therefore we could identify a team by some attribute of its parent series, such as the year or the MVP. The MVP might not be unique to the series, so let's make the key:

<xsl:key name="team-by-year" match="team" use="parent::series/@year" />

This says: if you tell me the year, I'll tell you the teams that played in the series of that year. So from here, it's simply a matter of calling a key with the current series' year:

<xsl:template match="/">
    <xsl:for-each select="ws/series">
        <xsl:value-of select="key('team-by-year', @year)[1]/@name" />
        <xsl:if test="position()!=last()">
            <xsl:text>&#10;</xsl:text>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

OTHER TIPS

If you use this

<xsl:stylesheet version='1.0' xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>

    <xsl:key name="winners" match="team[1]" use="@name" />

    <xsl:template match="/">
        <xsl:for-each select="ws/series/*">
            <xsl:value-of select="key('winners', @name)/@name" />
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top