2

Following is the original XML file that i need to transform. It's a list of music album records that I have to transform into an HTML table with the albums sorted in ascending order by year of issue and I need to make the connection with the genre and record label elements that are included in each individual record element as an id reference and output them in the table as well for each album.

In the second transform I need to do basically the same but in that case the output should include only albums from the Rock and the Pop genres.

    <?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="zadacha1.xsl" ?>
<record_collection>
    <genres>
        <genre id="1">Rock</genre>
        <genre id="2">Pop</genre>
        <genre id="3">Disco</genre>
        <genre id="4">Rap</genre>
        <genre id="5">Electronic</genre>
        <genre id="6">Country</genre>
    </genres>

    <record_labels>
        <record_label id="1">DGC Records</record_label>
        <record_label id="2">Atlantic</record_label>
        <record_label id="3">Epic</record_label>
        <record_label id="4">Warner Bros.</record_label>
        <record_label id="5">EMI</record_label>
        <record_label id="6">Columbia</record_label>
    </record_labels>

    <records>
        <record>
            <artist>Nirvana</artist>
            <genreID>1</genreID>
            <album>Nevermind</album>
            <year_of_issue>1992</year_of_issue>
            <record_labelID>1</record_labelID>
        </record>

        <record>
            <artist>Twisted Sister</artist>
            <genreID>1</genreID>
            <album>Stay Hungry</album>
            <year_of_issue>1984</year_of_issue>
            <record_labelID>2</record_labelID>
        </record>   

        <record>
            <artist>Michael Jackson</artist>
            <genreID>2</genreID>
            <album>Thriller</album>
            <year_of_issue>1982</year_of_issue>
            <record_labelID>3</record_labelID>
        </record>   

        <record>
            <artist>Bee Gees</artist>
            <genreID>3</genreID>
            <album>Spirits Having Flown</album>
            <year_of_issue>1979</year_of_issue>
            <record_labelID>4</record_labelID>
        </record>   

        <record>
            <artist>Ice-T</artist>
            <genreID>4</genreID>
            <album>O.G. Original Gangster</album>
            <year_of_issue>1991</year_of_issue>
            <record_labelID>4</record_labelID>
        </record>

        <record>
            <artist>Kraftwerk</artist>
            <genreID>5</genreID>
            <album>Computer World</album>
            <year_of_issue>1981</year_of_issue>
            <record_labelID>5</record_labelID>
        </record>

        <record>
            <artist>Johnny Cash</artist>
            <genreID>6</genreID>
            <album>Man in Black</album>
            <year_of_issue>1971</year_of_issue>
            <record_labelID>6</record_labelID>
        </record>

    </records>
</record_collection>

What I could manage was to output a non-sorted table without the genre and record label elements because they are linked through an id in each individual record and I don't know how to reach the id and output the text behind the id. Here's what I have up til now as my XSLT transform.

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/record_collection/records">
        <html>
         <head>
            <title>Records Collection</title>
         </head>
         <body>
            <h1>Records Collection</h1>
            <table border="1">
                <tr>
                    <th>Genre</th>
                    <th>Artist</th>
                    <th>Album</th>
                    <th>Year</th>
                    <th>Label</th>
                </tr>

                <xsl:apply-templates select="record" />
            </table>
            <xsl:call-template name="footer" />
         </body>
        </html>
    </xsl:template>

    <xsl:template match="record">
        <tr>
            <td>?</td>
            <td><xsl:value-of select="artist" /></td>
            <td><xsl:value-of select="album" /></td>
            <td><xsl:value-of select="year_of_issue" /></td>
            <td>?</td>
        </tr>
    </xsl:template>


    <xsl:template name="footer">
        <div style="margin: 20px 0; padding: 10px; background-color: #efefef; ">
            Record Collection
        </div>
    </xsl:template>

</xsl:stylesheet>
Rookie Programmer Aravind
  • 11,952
  • 23
  • 81
  • 114
Boyko Arsov
  • 341
  • 1
  • 5
  • 12

2 Answers2

2

You just have to use:

<xsl:apply-templates select="record">
    <xsl:sort select="year_of_issue" order="ascending" data-type="number"/>
</xsl:apply-templates>

instead of

<xsl:apply-templates select="record"/>

The table will be sorted in ascendig order by year of issue

nunure
  • 46
  • 9
1

This is a good place to use xsl:key to lookup your genres and record labels

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">
        <xsl:apply-templates select="/record_collection/records"></xsl:apply-templates>
    </xsl:template>

    <xsl:key name="genre-lookup" match="/record_collection/genres/genre" use="@id"/>
    <xsl:key name="record_label" match="/record_collection/record_labels/record_label" use="@id"/>

    <xsl:template match="records">
        <html>
            <head>
                <title>Records Collection</title>
            </head>
            <body>
                <h1>Records Collection</h1>
                <table border="1">
                    <tr>
                        <th>Genre</th>
                        <th>Artist</th>
                        <th>Album</th>
                        <th>Year</th>
                        <th>Label</th>
                    </tr>

                    <xsl:apply-templates select="record" />
                </table>
                <xsl:call-template name="footer" />
            </body>
        </html>
    </xsl:template>

    <xsl:template match="record">
        <tr>
            <td>
                <xsl:value-of select="key('genre-lookup',genreID)" />
            </td>
            <td>
                <xsl:value-of select="artist" />
            </td>
            <td>
                <xsl:value-of select="album" />
            </td>
            <td>
                <xsl:value-of select="year_of_issue" />
            </td>
            <td>
                <xsl:value-of select="key('record_label',record_labelID)" />
            </td>
        </tr>
    </xsl:template>


    <xsl:template name="footer">
        <div style="margin: 20px 0; padding: 10px; background-color: #efefef; ">
            Record Collection
        </div>
    </xsl:template>

</xsl:stylesheet>

If you just want to filter by Rock or Pop, then adjust your apply-templates to filter just by genreId = 1 / 2:

<xsl:apply-templates select="record[genreID=1 or genreID=2]" />

One minor change to your original xslt is to capture the root, in order to prevent the default processing instructions being applied to the document.

StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • 1
    A big thanks for your help buddy :) !!! Just one more thing - after the transformation, on the top of the document are left the entries from the "genres" and "record labels" categories. How do I stop them from displaying in the transformed document? – Boyko Arsov Nov 27 '12 at 15:59
  • 1
    @GrigorPetrov - this is the affect of the [default built in templates](http://stackoverflow.com/questions/3360017/why-does-xslt-output-all-text-by-default). Adding a 'root' template which does `apply-templates` to just the nodes you are interested in solves this (I've done this in my answer) – StuartLC Nov 27 '12 at 16:02