Book Chapters à la Carte
Long texts such as books, standards documents, and user manuals are typically organized in chapters and sections. By exploiting this inherent structure, XSSI can provide an all-inclusive/printer-friendly version of the entire text; furnish each book chapter independently; and allow users to read any assortment of chapters à la carte. This portioning method is a form of basic content management, which allows for increased usability--making it possible to deliver long documents in palatable pieces while keeping the number of maintainable and updatable documents to a minimum.
To further illustrate the partitioning method using XSSI, consider a presentation of some text from the first book of Charles Dickens's A Tale of Two Cities, which is freely available from Project Gutenberg. Following the terminology used in the previous section, each book chapter becomes a part in the presentation. Chapter 1 is available through the URL
Chapter 2 is available from
and so on. Of course, a good application should also generate dynamic links between chapters (Previous/Next). A printer-friendly version of the entire book is available via
while a printer-friendly version of the first chapter only is available at
Finally, there's one more feature: if the user would like to read chapters 2 and 3 in one go, then she can do so by requesting:
Figure 2 illustrates the opening page of the book, which contains the table of contents, an action button (titled "View selected"), and a link to a printer-friendly version of the entire book. The table of contents includes links to each chapter separately and check boxes that can be used to select a subset of chapters. Note that users can address and bookmark all these different views of the same document independently, yet the entire text is still in a single file (Listing 16).
Figure 2. The best and worst of times
Listing 16. Book chapters à la carte using XSSI
<html> <head> <!--#include file="meta.shtml" --> <link rel="stylesheet" href="<!--#echo var='view'-->.css" type="text/css"> <!--#set var="title" value="A Tale of Two Cities" --> <title><!--#echo var="title" --></title> </head> <body> <h1 id="top"><!--#echo var="title" --></h1> <p>A story of the French Revolution by Charles Dickens.</p> <h2>Book the First--Recalled to Life</h2> <!--#if expr="$view != print" --> <form method="GET"> <p><input type="submit" value="View selected"></p> <p><input type="checkbox" name="p" value="1"> <a href="?p=1">I. The Period</a><br /> <input type="checkbox" name="p" value="2"> <a href="?p=2">II. The Mail</a><br /> <input type="checkbox" name="p" value="3"> <a href="?p=3">III. The Night Shadows</a><br /> ... <p><input type="submit" value="View selected"></p> </form> <!--#endif --> <!--#if expr="$QUERY_STRING = /p\=1/ || $QUERY_STRING= print" --> <h3>I. The Period</h3> <p>It was the best of times, it was the worst of times, ...</p> <!--#set var="next" value="p=2" --> <!--#include file="back2top.shtml" --> <!--#endif --> <!--#if expr="$QUERY_STRING = /p\=2/ || $QUERY_STRING = print" --> <h3>II. The Mail</h3> <p>It was the Dover road that lay, ...</p> <!--#set var="previous" value="p=1" --> <!--#set var="next" value="p=3" --> <!--#include file="back2top.shtml" --> <!--#endif --> <!--#if expr="$QUERY_STRING = /p\=3/ || $QUERY_STRING = print" --> <h3>III. The Night Shadows</h3> <p>A wonderful fact to reflect upon, ...</p> <!--#set var="previous" value="p=2" --> <!--#include file="back2top.shtml" --> <!--#endif --> <!--#if expr="$view != print && $QUERY_STRING != /&p\=/" --> <p> <!--#if expr="$previous" --> <a href="?<!--#echo var="previous" -->">previous</a> | <!--#endif --> <!--#if expr="$next" --> | <a href="?<!--#echo var="next" -->">next</a> <!--#endif --> </p> <!--#endif --> <!--#include file="book-tools.shtml" --> </body> </html>
The partitioning code is similar to that of the previous section. For example, the first part will display if the condition
<!--#if expr="$QUERY_STRING = /p\=1/ || $QUERY_STRING= print" -->
is true. Chapter 1 will display if
p=1 is present anywhere in
$QUERY_STRING; that is, when requested either as a single chapter
or as part of a collection of chapters with
Note that code has to escape the equal sign in this conditional
\=) in order to differentiate the character equal sign in the
p=1 from the operator equal sign. Alternatively, the first
chapter will display if the user requests the entire book in printer-friendly
format. Listing 16 also includes code for generating the navigational labels
(Previous/Next) and links that take the user back to the top of the page
(and should not appear in the printer-friendly versions) as shown in Listing
Listing 17. Back to the top
<!--#if expr="$view != print" --> <p><a href="#top">Back to top ⇑</a></p> <!--#endif -->
Finally, the code includes Listing 18, which generates links to the printer-friendly versions. The label "Print this" appears only when the user views a single chapter or a set of chapters, but not the opening screen (Figure 2).
Listing 18. Book-tools revealed
<!--#if expr="$view != print" --> <p> <!--#if expr="$QUERY_STRING = /p\=/" --> <a href="?print&<!--#echo var='QUERY_STRING' -->">Print this</a> - <!--#endif --> <a href="?print">Print entire book</a></p> <!--#endif -->
The principle presented here applies to scores of different applications. For example, a bus operator web site can provide customized schedules using XSSI only. In this scenario, the schedule to and from a particular end point is stored in a single document with the timetables for weekdays and weekends forming the different parts of the text. In a fashion similar to the Dickens example, a passenger traveling out of town for the weekend may choose to get a printout of the Friday (weekday) timetable to her destination along with the Sunday (weekend) timetable from her destination. The site can go one step further and use time/date information to present today's schedule by default. Traveling directions can also be partitioned, for example, based on the different means of transportation. In this case, all parts may share some common text, such as the destination address and phone number, without the need to store this information and replicate it in several places.
As a last example, consider the web site of a registered charity that accepts donations via several different methods such as small cash, check, or credit card donations, automatic paycheck withholdings, and planned giving. The charity would like to offer online details about each method. Of course, this wide range of options comes with a diverse set of rules and regulations, which may force some designers to create different pages for each category--a decision that usually increases future maintenance time. Moreover, it is convenient to be able to pick and choose the method that is more interesting to a potential donor. Using the partitioning method above, the site can include details on all possible donation procedures in a single document while delivering customized "web brochures" to donors.
All XSSI solutions, including the partitioning method, can work with client-side scripting to enhance certain aspects of the application, if required. In addition, you can also generate the content itself offline using back-end solutions. For example, your content producers may edit the document using a wiki environment run on the company intranet server. At regular intervals, a back-end application may check for updates on the wiki and, if there are any, generate the XSSI-enriched document for publishing on the public company web site. That way, you can enforce document control via the wiki, which makes the public server content more secure, because a bare-bones Apache with XSSI enabled is less complex and in general more mature and robust than wiki environments. In addition, you can deliver the web site content with fewer hardware and software requirements, as there is no need for a document database. This is an efficient cost-cutting solution, because the web site can serve more users with the same configuration.
Hierarchical Menus with XSSI
This section proposes an alternative implementation of hierarchical menus using XSSI. The main advantage with XSSI is that client make, capabilities, or configuration options do not affect the look and feel of the site at all. The menus will work just fine, because the final product is pure markup and the browser does not need to execute any client-side code. You will also get the coolness factor, at least to some extent. Moreover, the site will load significantly faster, because users will download only the menu items that they are interested in instead of downloading all menus and submenus at once. Last, the XSSI implementation presented below enforces structured thinking while laying down the site design, which leads to well-organized, functional web sites.
Assume that you are building a site that provides information on the planets of the solar system, the greater geographical areas on each planet (aka continents for Earth), and the political subdivisions in each area (countries). Clearly the content size in each category, and hence in each menu, is quite unbalanced. This, of course, is the case with most real-world web sites: some sections of the content are richer and more elaborate (Our Products or Our Services sections of corporate sites); others are bare-bones (the omnipresent Contact Us).
Table 2, Column a, shows a good candidate for this site's first-level, left-side vertical menu. Each planet is a link, an item in the menu, which when selected leads to the corresponding page. The heading Solar System is also a menu item. When the user selects Earth, the corresponding page loads and the relevant submenu opens up, displaying the second-level menu items (column b), the continents. Similarly, when the user selects Africa, the third-level menu (column c) opens up, displaying the list of African countries along with information on Africa.
Table 2. Hierarchical menus illustrated
This menu structure is easy to translate into a directory structure, which I will exploit as follows. Each of the menu items maps to a directory in the implementation, and each directory has a single document titled index.shtml that includes the menu and the corresponding text. Listing 19 presents the outline of every such document.
Listing 19. Page template
<html> <head><title>Solar System</title></head> <body> <!--#include virtual="/menu.shtml" --> <p>Content particular to the Solar System... </body></html>
Although this may seem a bit restrictive, it is not a prerequisite--it
simply eases the presentation in this tutorial. The only XSSI directive is the
familiar file inclusion. Notice that instead of including the
menu.shtml, the code includes its
virtual location on the
site. Where is all the magic, you ask? That happens in
menu.shtml, presented in Listing 20. Each menu item is listed with the
corresponding link, and each item that has subcategories conditionally includes
the relevant submenu. This submenu displays only when the requested document is
under the corresponding hierarchy.
Listing 20. The first-level hierarchical menu implementation includes the menu items ("Solar System") and, where needed, conditional inclusions of the relevant submenus
<p><a href="/">Solar System</a></p> <ul> <li><a href="/mercury">Mercury</a></li> <li><a href="/venus">Venus</a></li> <li><a href="/earth">Earth</a> <!--#if expr="$REQUEST_URI = /earth/" --> <!--#include virtual="/earth/menu.shtml" --> <!--#endif --> </li> <li><a href="/mars">Mars</a></li> ... </ul>
For example, if the user requests the main page of the site:
Listing 20 will display the opening page with information on the solar system and the menu as shown in Table 2, Column a. The submenu for Earth will not display. In contrast, when the user clicks on the link for Earth, she effectively requests
and the submenu shown in Listing 21 will be included and the full menu will display as in Table 2, Column b. Again, the menu.shtml found that the earth directory contains the links to the menu items (Africa, Antarctica) and a conditional submenu inclusion where appropriate. Finally, if the user clicks on Africa, she is effectively requesting
In that case, the complete submenu will be display as in Table 2, Column c.
Listing 21. Second-level submenu ("Earth")
<ul> <li><a href="/earth/africa">Africa</a> <!--#if expr="$REQUEST_URI = /africa/" --> <!--#include virtual="/africa/menu.shtml" --> <!--#endif --> </li> <li><a href="/antarctica">Antarctica</a></li> ... </ul>
Listing 22. Third-level submenu ("Africa")
<ul> <li>Algeria</li> <li>Angola</li> <li>Benin</li> ... <li>Zimbabwe</li> </ul>
Effectively, this hierarchical menu's implementation takes advantage of the directory structure and conditional recursive file inclusions, delivering a simple yet powerful navigational aid. You can extend submenus and add new menu items on demand. Maintaining the menus is straightforward because the menu reflects the directory structure. In fact, you could even develop a back-end solution to create menus and the corresponding directory structure based on configuration files along the lines discussed in the previous section.
Although this tutorial presents several solutions based on XSSI, it does not cover configuration issues. If you are responsible for setting up XSSI on a server, your first reading should probably be the Apache Tutorial: Introduction to Server Side Includes. This excellent yet brief tutorial explains how to configure Apache to run XSSI and introduces several commands along with examples of typical usage. The Apache Module mod_include documentation is a great resource as well.
The NCSA HTTPd Tutorial: Server Side Includes introduces SSI as a technology that allows users "to provide simple information on the fly." The NCSA HTTPd is a web server that is now obsolete but is, after all, the granddaddy of Apache. This tutorial is from 1995 and is mostly of historical value today. Do pay attention to the warnings about security, but bypass the caveats about performance: every dynamic content technology places a burden on the server typically, as mentioned in the introduction, much heavier than XSSI.
The tutorial Using XSSI and ErrorDocument to configure customized international server error responses makes for very interesting reading and can give you many ideas for your applications. The XSSI Library by Ross Olson is full of recipes, tips, and code samples. For example, Olson categorized the 30-plus environment variables you can use in your XSSI code and lists them along with a short description and examples Finally, the Apache Hello World Benchmarks has more details than I mentioned in the beginning of the tutorial.
Kostas Pentikousis is currently an ERCIM Fellow at VTT, The Technical Research Center of Finland, and resides in Oulu, Finland.
Return to the Apache DevCenter.