Overview of the Assignment

The Dracula team is working on tagging locations, technology, dates, times, and more in Bram Stoker’s novel Dracula, and we will work with their project code create a reading view that includes a reading view of the novel as well as an information-rich table of contents to summarize the contents of their tagging so far. If you are working on a different project, you may opt to adapt the code we are modeling with Dracula to your own XML for this assignment.

Open the XML file in <oXygen/> and study its code, and take some notes about where you can find the information destined for the target output in HTML.

It may also help to orient yourself to HTML table coding. HTML tables are organized in rows, using <tr> elements, which contain <td> elements (which means table data). You control the columns in an HTML table by the setting the <td> cells in an ordered sequence. Inside a <tr>, the first <td> is set in column 1, the second <td> in column 2, the third in column 3, and so on. The top row conventionally contains headings in <th> cells, which HTML will emphasize by default. Here is a simple HTML table (styled following our newtfire CSS, in which I’ve outlined the borders and given a background color to the table heading cells). Next to it is a view of the HTML code that creates the table structure:

Heading 1 Heading 2 Heading 3
Row 1, cell 1 Row 1, cell 2 Row 1, cell 3
Row 2, cell 1 Row 2, cell 2 Row 2, cell 3
         <table>
          <tr>
             <th>Heading 1</th>
             <th>Heading 2</th>
             <th>Heading 3</th>
          </tr>
          <tr>
             <td>Row 1, cell 1</td>
             <td>Row 1, cell 2</td>
             <td>Row 1, cell 3</td>
          </tr>
          <tr>
             <td>Row 2, cell 1</td>
             <td>Row 2, cell 2</td>
             <td>Row 2, cell 3</td>
          </tr>
       </table>

Before You Begin: Set up the XSLT Stylesheet to Output HTML

To ensure that the output will be in the XHTML namespace, we need to add a default namespace declaration (in purple below). To output the required DOCTYPE declaration, we also need to set the <xsl:output> element as a child of our root <xsl:stylesheet> element (in blue below), and we needed to include an attribute there to omit the default XML declaration because if the XML line shows up in our XHTML output, it will not produce valid HTML with the w3C and might produce quirky problems with rendering in various web browsers. So, our modified stylesheet template and xsl:output line is this, and you should copy this into your stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
         <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
    xmlns="http://www.w3.org/1999/xhtml">
    
    <xsl:output method="xhtml" encoding="utf-8" doctype-system="about:legacy-compat"
        omit-xml-declaration="yes"/>
    
    </xsl:stylesheet>

Guide to writing the XSLT

Start with the reading view

At first, forget about the modal XSLT and just start by processing the reading view of Dracula. In many ways, for processing Dracula, this is easier than your previous assignments, and it involves processing richly mixed content without needing to target it selectively. Here is what we intend to capture from the Dracula team’s markup (though you may wish to adapt this to your own project markup and make yourself a checklist before you begin):

Modal XSLT for the Table of Contents

The template rule for the document node in our solution, revised to output a table of contents with all the information we wish to show before the text of the poems, looks like the following:

    <xsl:template match="/">
     <html>
         <head>
             <title>Dracula</title>
             <link rel="stylesheet" type="text/css" href="style.css"/>
         </head>
         <body>
           <h1><xsl:apply-templates select="descendant::title"/></h1>
             
             <!--ebb: Table of contents here. -->
            <table> 
             <tr>
                 <th>Chapter Number</th>
                 <th>Locations mentioned</th>
                 <th>Tech mentioned</th>
             </tr>
                <xsl:apply-templates select="descendant::chapter" mode="toc"/>
    <!--ebb: This xsl:apply-templates line sets up my "toc" mode for the table of contents, 
so that in the top part of the document we’ll output a selection of the body elements 
specially formatted for my Table of Contents, and so that in another section of my document below, 
which I’ve put inside an HTML <section> element, 
we can also output the full text of the poems with their titles again.-->
                
            </table>
             
             <!--ebb: Reading view of the chapters here. -->
             <xsl:apply-templates select="descendant::chapter"/>
        </body>
     </html>
 </xsl:template>

The highlighted code is what we added to include a table of contents, and the important line is <xsl:apply-templates select="descendant::chapter" mode="toc"/>. This is going to apply templates to each chapter with the @mode attribute value set to toc. The value of the @mode attribute is up to you (we used toc for table of contents), but whatever you call it, setting the @mode to any value means that only template rules that also specify a @mode with that same value will fire in response to this <xsl:apply-templates> element. Now we have to go write those template rules!

What this means is that when you process the <body> elements to output the full text of the chapters, you use <xsl:apply-templates> and <xsl:template> elements without any @mode attribute. To create the table of contents, though, you can have <xsl:apply-templates> and <xsl:template> elements that select or match the same elements, but that specify a mode and apply completely different rules. A template rule for <chapter> elements in table-of-contents mode will start with <xsl:template match="chapter" mode="toc">, and you need to tell it to create a <tr> element with some nested td elements to match the table heading rows you set up earlier:

    <xsl:template match="chapter" mode="toc">
        <tr>
            <td><!--Output the chapter heading here. 
When we are ready we will create a link here to jump from the chapter heading to its target id coded in the chapter heading in the reading view.--> </td>
            <td><!--Output a string-joined list of distinct locations here?-></td>
            <td><!--=Output a string-joined list of tech mentioned here?--></td>   
         </tr>
    </xsl:template> 
   

The rule for processing those same elements not in any mode will start with <xsl:template match="chapter"> (without the @mode attribute). That rule will create the HTML <h2> to output the text of the chapter <heading> element and then apply-templates again to select the <p> elements for processing as HTML <p> elements. In this way, you can have two sets of rules for this document: one for the table of contents and one to output the full text in a reading view, and we use modes to ensure that each is used only in the correct place.

Remember: both the <xsl:apply-templates>, which tells the system to process certain nodes, and the <xsl:template> that responds to that call and does the processing must agree on their mode values. For the main output of the full text of every chapter, neither the <xsl:apply-templates> nor the <xsl:template> elements specifies a mode. To output the table of contents, both specify the same mode.

Completing and checking your work