nod64
nod64

Reputation: 61

muenchian grouping nodes at different level

I have an xml file similar to the one below and I want to group the correct teams and players together using XSLT 1.0. But instead of displaying the correct players under their relevant teams, it displays all players under all teams.

I know it has different node sets inside the root element which is possibly the reason the grouping is not working, I'm not even sure if this is possible, the examples of muenchian grouping all seem to have a single node set inside the root element.

The XML

    <?xml version="1.0" encoding="utf-8"?>
    <?xml-stylesheet type="text/xsl" href="football.xslt"?>

    <football>
                    <!-- team details go here -->
      <teams>
        <team teamCode="#ASNL">
          <teamName>Arsenal</teamName>
          <stadium>Emirates Stadium</stadium>
          <location>North London</location>
        </team>

        <team teamCode="#NUTD">
          <teamName>Newcastle United</teamName>
          <stadium>St James' Park</stadium>
          <location>Newcastle Upon Tyne</location>
        </team>
      </teams>
                      <!-- end of teams -->

                   <!-- player details go here -->
      <players>
        <player teamID="#ASNL">
          <playerFirstName>Hector</playerFirstName>
          <playerSurname>Bellerin</playerSurname>
          <position>RB</position>
          <goals>3</goals>
          <assists>5</assists>
        </player>

        <player teamID="#ASNL">
          <playerFirstName>Mesut</playerFirstName>
          <playerSurname>Ozil</playerSurname>
          <position>CAM</position>
          <goals>10</goals>
          <assists>20</assists>
        </player>

        <player teamID="#NUTD">
          <playerFirstName>Papiss</playerFirstName>
          <playerSurname>Cisse</playerSurname>
          <position>CF</position>
          <goals>15</goals>
          <assists>5</assists>
        </player>

        <player teamID="#NUTD">
          <playerFirstName>Tim</playerFirstName>
          <playerSurname>Krul</playerSurname>
          <position>GK</position>
          <goals>0</goals>
          <assists>3</assists>
        </player>
      </players>
                            <!-- end of players -->

    </football>

The XSLT

<?xml version="1.0" encoding="utf-8" ?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html"/>
  <xsl:key name="teamKey" match="team" use="@teamCode"/>


  <xsl:template match="/">

    <xsl:for-each select="/football/teams/team[generate-id(.)=generate-id(key('teamKey', @teamCode)[1])]">
      <xsl:sort select="teamName"/>

      <teamDetails>
        <br />
        <b>Team Name: </b>
        <xsl:value-of select="teamName"/>
        <br />
        <b>Stadium: </b>
        <xsl:value-of select="stadium"/>
        <br />
        <b>Location: </b>
        <xsl:value-of select="location"/>
        <br />
      </teamDetails>

      <table>
        <br />
        <tr>
          <th>First Name</th>
          <th>Surname</th>
          <th>Position</th>
          <th>Goals</th>
          <th>Assists</th>
        </tr>

        <xsl:for-each select="/football/players/player[key('teamKey', @teamID)]">
          <tr>
            <td>
              <xsl:value-of select="playerFirstName"/>
            </td>
            <td>
              <xsl:value-of select="playerSurname"/>
            </td>
            <td>
              <xsl:value-of select="position"/>
            </td>
            <td>
              <xsl:value-of select="goals"/>
            </td>
            <td>
              <xsl:value-of select="assists"/>
            </td>
          </tr>
        </xsl:for-each>
      </table>
    </xsl:for-each>

  </xsl:template>
</xsl:stylesheet>

Upvotes: 0

Views: 115

Answers (2)

michael.hor257k
michael.hor257k

Reputation: 116959

I'd suggest you do it this way:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8"/>

<xsl:key name="player-by-team" match="player" use="@teamID"/>

<xsl:template match="/football">
    <xsl:for-each select="teams/team">
        <xsl:sort select="teamName"/>
        <b>Team Name: </b>
        <xsl:value-of select="teamName"/>
        <br />
        <b>Stadium: </b>
        <xsl:value-of select="stadium"/>
        <br />
        <b>Location: </b>
        <xsl:value-of select="location"/>
        <br />
        <table>
            <tr>
                <th>First Name</th>
                <th>Surname</th>
                <th>Position</th>
                <th>Goals</th>
                <th>Assists</th>
            </tr>
            <xsl:for-each select="key('player-by-team', @teamCode)">
                <tr>
                    <td>
                        <xsl:value-of select="playerFirstName"/>
                    </td>
                    <td>
                        <xsl:value-of select="playerSurname"/>
                    </td>
                    <td>
                        <xsl:value-of select="position"/>
                    </td>
                    <td>
                        <xsl:value-of select="goals"/>
                    </td>
                    <td>
                        <xsl:value-of select="assists"/>
                    </td>
                </tr>
            </xsl:for-each>
        </table>
        <br />
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Upvotes: 1

hr_117
hr_117

Reputation: 9627

No need for any muenchian grouping her:

Change the first loop for the teams to (and have a variable for the current team):

<xsl:for-each select="/football/teams/team">
  <xsl:sort select="teamName"/>
  <xsl:variable name="thisTeam" select="." />

And than the second loop for players within the team to:

 <xsl:for-each 
        select="/football/players/player[ @teamID  = $thisTeam/@teamCode ]">

Upvotes: 1

Related Questions