Alex
Alex

Reputation: 876

XSLT - interlink attributes from different child elements

I have the following XML file that stores movies and actors:

<database
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="movies.xsd">
    <movies>
        <movie movieID="1">
            <title>Movie 1</title>
            <actors>
                <actor actorID="1"></actor>
                <actor actorID="2"></actor>
            </actors>
        </movie>
    </movies>

    <actors>
        <actor actorID="1">
            <name>Bob</name>
        </actor>
        <actor actorID="2">
            <name>Mike</name>
        </actor>
    </actors>
</database>

I want to connect actorID from database/movies/movie/actors/actor with the actorID from database/actors/actor and display actors' names:

This is my XSLT:

<xsl:variable name="selectActors" select="database/actors/actor[@actorID]"/>
<xsl:variable name="inputRoot" select="/"/>

<xsl:template match="/">
    <xsl:apply-templates select="database/movies/movie"/>
</xsl:template>

<xsl:template match="movie">
        Title:
        <xsl:value-of select="title"/>
        <br/>
        Actors:
        <xsl:for-each select="actors/actor[@actorID=$selectActors]">
            <xsl:value-of select="$inputRoot/database/actors/actor/name"/>
            <br/>
        </xsl:for-each>
        <br/>
</xsl:template>

This is the end result that I want to display:

Title: Movie 1
Actors: Bob
    Mike

I cannot get actor names to display on my page. I am not sure if I have interlinked my actorID's correctly as I'm very new to XSLT in general.

Upvotes: 0

Views: 128

Answers (1)

JLRishe
JLRishe

Reputation: 101730

There is a problem with the XPath in your for-each and the one in your value-of but a more efficient (and more elegant) approach than what you're attempting is to use keys:

<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="kActor" match="database/actors/actor" use="@actorID"/>

  <xsl:template match="/">
    <div>
      <xsl:apply-templates select="database/movies/movie"/>
    </div>
  </xsl:template>

  <xsl:template match="movie">
    <xsl:value-of select="concat('Title: ', title)"/>
    <br />
    <xsl:text>Actors: </xsl:text>
    <xsl:apply-templates select="key('kActor', actors/actor/@actorID)" />
    <br />
  </xsl:template>

  <xsl:template match="actor">
    <xsl:value-of select="name"/>
    <br />
  </xsl:template>
</xsl:stylesheet>

When run on your sample input, the result is:

<div>
  Title: Movie 1<br />Actors: Bob<br />Mike<br /><br />
</div>

And just so you can see what was incorrect with your XPath, here is how you could have fixed your existing solution to work correctly:

<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:variable name="selectActors" select="database/actors/actor"/>

  <xsl:template match="/">
    <div>
      <xsl:apply-templates select="database/movies/movie"/>
    </div>
  </xsl:template>

  <xsl:template match="movie">
    Title:
    <xsl:value-of select="title"/>
    <br/>
    Actors:
    <xsl:for-each
      select="$selectActors[@actorID = current()/actors/actor/@actorID]">
      <xsl:value-of select="name"/>
      <br/>
    </xsl:for-each>
    <br/>
  </xsl:template>
</xsl:stylesheet>

Upvotes: 1

Related Questions