0

I have an xml file about movies that looks like this (short version)

    <movie id="movie_tt0004994">
       <title>Bound on the Wheel </title>
       <stars idref="star_nm0933368 star_nm0913085 star_nm0151606"/>
    </movie>
    <star id="star_nm0933368">
       <name>Elsie Jane Wilson</name>
    </star>

I want to transform this xml into html, using xslt. The html should be a table with the movie title in the first column, and the star NAMES (which are at most 3) in the following three columns.

 <?xml version="1.0" encoding="UTF-8"?>
 <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
 <xsl:template match="/">
 <html>
 <body>
 <h2>movie list</h2>
 <table border="1">
 <th>Title</th>
 <th colspan="3">Stars</th>
 </tr>
 <xsl:for-each select="IMDb/movie">
 <tr>
 <td><xsl:value-of select="title" /></td>
 <xsl:for-each select="stars/@idref">
 <xsl:variable name="curr_ref" select="."/>
 <td><xsl:value-of select="//IMDb/star[@id=$curr_ref]/name"/></td>
 </xsl:for-each>    
 </tr>
 </xsl:for-each>    
 </table>
 </font>
 </body>
 </html>
 </xsl:template>
 </xsl:transform>

The problem is that it only works for movies with one star. If there are multiple star ids in stars (like in the movie in the given part of my xml) then the corresponding columns in my table remain empty. I think this is because the line then makes curr_ref one long string of all the idrefs instead of three seperate ones. How should I go about this?

Lisa
  • 1
  • 1
  • Are you restricted to XSLT 1.0? Or can you use XSLT 2.0 with e.g. `` and e.g. `...`? – Martin Honnen Nov 25 '16 at 14:14
  • Certainly, the preferred solution would be to change your XML schema, because for storing a number of items, a collection of **nodes** should be used (instead of storing them with character-level separators). – Little Santi Nov 25 '16 at 14:14
  • @LittleSanti, the schema language has a type https://www.w3.org/TR/xmlschema-2/#IDREFS which is a sequence of space separared IDREF values so assuming a schema the presentation is fine. Only schema-aware XSLT 2.0 is not as broadly supported as general XSLT 2.0 as for instance with Saxon 9 only EE supports schema-aware XSLT 2.0 or 3.0. – Martin Honnen Nov 25 '16 at 14:48
  • @MartinHonnen OK. Good to know. Thanks. – Little Santi Nov 25 '16 at 18:37

1 Answers1

2

Assuming XSLT 2.0 you can use

<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:key name="star" match="star" use="@id"/>

 <xsl:template match="/">
 <html>
 <body>
 <h2>movie list</h2>
 <table border="1">
 <tr>
 <th>Title</th>
 <th colspan="3">Stars</th>
 </tr>
 <xsl:for-each select="IMDb/movie">
 <tr>
 <td><xsl:value-of select="title" /></td>
 <xsl:for-each select="for $ref in tokenize(stars/@idref, '\s+') return key('star', $ref)">
 <td><xsl:value-of select="name"/></td>
 </xsl:for-each>    
 </tr>
 </xsl:for-each>    
 </table>
 </body>
 </html>
 </xsl:template>

 </xsl:transform>

Assuming XSLT 1.0 (or later) and DTD support you can use

<!DOCTYPE IDMb [
<!ATTLIST star
  id ID #REQUIRED>
<!ATTLIST stars
  idref IDREFS #REQUIRED>
]>

<IMDb>
<movie id="movie_tt0004994">
       <title>Bound on the Wheel </title>
       <stars idref="star_nm0933368 star_nm0913085 star_nm0151606"/>
    </movie>
    <star id="star_nm0933368">
       <name>Elsie Jane Wilson</name>
    </star>
</IMDb>

and

 <xsl:template match="/">
 <html>
 <body>
 <h2>movie list</h2>
 <table border="1">
 <tr>
 <th>Title</th>
 <th colspan="3">Stars</th>
 </tr>
 <xsl:for-each select="IMDb/movie">
 <tr>
 <td><xsl:value-of select="title" /></td>
 <xsl:for-each select="id(stars/@idref)">
 <td><xsl:value-of select="name"/></td>
 </xsl:for-each>    
 </tr>
 </xsl:for-each>    
 </table>
 </body>
 </html>
 </xsl:template>
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110