XQuery/Slideshow
Motivation
[edit | edit source]Despite being a 20-year old program, albeit enhanced over the years, Microsoft PowerPoint is the ubiquitous presentation software. It provides a wide range of functionality, but most of us use it for simple text slides, perhaps with a bit of animation.
However Powerpoint does not cleanly separate the content of the presentation from its presentation (as slides, in printed form, as a index) and appearance (styles, colors), is an expensive proprietary product and over-weight for many tasks. Thus there is value in using simple XML tools to provide similar functionality.
Prior art
[edit | edit source]There are a number of approaches to using XML technologies to provide light-weight, non-proprietorial presentation software. These typically rely on a web browser as the rendering engine (a design choice not open to Richard Gaskins in 1984). Core problems are the task of dividing the presentation into separate slides and supporting navigation in the slide sequence.
- Slidy by Dave Raggett - SlidyXML, XSLT, Javascript
- S5 by Eric Meyer
- DocBook by Norman Walsh - DocBook, XSLT
- [1] DocBook, CSS, Opera presentation mode
This project uses XQuery as the server-side language.
Presentation format
[edit | edit source]Other approaches use a defined vocabulary but the choice here is to use XHTML with a little additional markup to define slide boundaries and slideshow properties. This provides a wide range of functionality needed such as formating, linking, images, embedded video.
<ss:slideshow xmlns="http://www.w3.org/1999/xhtml" xmlns:ss="http://www.cems.uwe.ac.uk/xmlwiki/slideshow">
<ss:css>
<ss:slide>slide.css</ss:slide>
<ss:print/>
</ss:css>
<ss:header>DSA 2008 - Lecture 1 - Chris Wallace</ss:header>
<ss:footer/>
<ss:slide>
<h1>Teaching approach</h1>
<ul>
<li>1 lecture a week
<ul>
<li>Interaction using SMS whiteboard and Multi-choice cube</li>
</ul>
</li>
<li>1 2-hour workshop every 2 weeks - write down the weeks you have been allocated</li>
<li>2 hour Research time every 2 weeks (alternating with the workshops) - independent
study with tutor support </li>
<li>Teaching resources in UWEOnline and in the <a href="https://www.cems.uwe.ac.uk/studentwiki/index.php/UFIEKG-20-2/2008">studentWiki</a>
</li>
</ul>
</ss:slide>
...
Here I have used two namespaces: the default is the XHTML used in the slide body, the ss namespace is used for the slideshow elements which define slideshow properties, master slide, and the slide boundaries.
This is a very minimal format which would be expanded in future.
The Script
[edit | edit source]The XML document defining the slideshow content needs to be transformed into slides for projection and into a print format. In this implementation, both versions are generated from the same script.
Namespaces
[edit | edit source]The two namespaces must be declared - an arbitrary prefix used for the default XHTML namespace.
declare namespace ss= "http://www.cems.uwe.ac.uk/xmlwiki/slideshow";
declare namespace h = "http://www.w3.org/1999/xhtml" ;
Parameters
[edit | edit source]The slide parameters are the uri of the slideshow document (whether a database document or an external document), the slide number and the mode - slide or print. The parameters are passed in a semicolon-delimited query string rather than in the more usual key=value form because I was unable to get the & separator to work in Javascript(??)
declare variable $params := tokenize(request:get-query-string(),";");
declare variable $uri := $params[1];
declare variable $n := xs:integer(($params[2],1)[1]);
declare variable $mode :=($params[3],"slide")[1];
Fetching the XML
[edit | edit source]The slideshow is fetched - this is faster if stored in the database but may also be an external file.
declare variable $slideshow := doc($uri)/ss:slideshow;
declare variable $slides := $slideshow/ss:slide;
declare variable $count := count($slides);
The Slide Show
[edit | edit source]Show a Slide
[edit | edit source]A function generates the div holding a slide. The global variables define the common slideshow properties.
declare function local:show-slide($slide as element(ss:slide) ) as element(div) {
<div class="slide">
<span class="header">{$slideshow/ss:master/ss:header/node()}</span>
{$slide}
<span class="footer">{$n}/{$count}   {$slideshow/ss:footer/node()} </span>
</div>
};
Contents Slide
[edit | edit source]The <h1> element in each slide is used to generate a contents slide, numbered 0.
declare function local:show-contents() as element(div) {
<div class="contents">
<span class="header">{$slideshow/ss:header/node()}</span>
<h1>Contents</h1>
<ul>
{for $slide at $i in $slides
return
<li>{$i}  <a href="slide.xql?{$uri};{$i}">{string($slide/h:h1)}</a> </li>
}
</ul>
<span class="footer">0/{$count}   {$slideshow/ss:footer/node()} </span>
</div>
};
Navigation
[edit | edit source]Navigation is handled by a JavaScript function which handles keypress events and is attached to the page body. This code is different for each slide so is generated for each slide. The keypress mapping is based partly on the codes generated by a common wireless presenter, the Labtec Notebook presenter which is designed for use with PowerPoint. Documentation on the device was hard to find, so the key mapping was analysed by capturing the keypresses observed by a simple javascript.
- left and right buttons: PageUp and PageDown to step forwards and backwards
- bottom key : 'b' to blank the screen
- top button : toggle between F5 to fullscreen, Esc to edit mode
Other key mappings were added to allow the cursor keys to be used and to go to print mode.
Note that in generating this Javascript code, { } brackets need to be doubled.
declare function local:keypress-script() as element(script) {
let $prev := if ($n > 0) then $n - 1 else 1
let $next := if ($n < $count) then $n + 1 else $count
return
<script type="text/javascript">
function keypress(e) {{
var code=e.keyCode
if (code==34 || code== 39) document.location = "slide.xql?{$uri};{$next}" //Page UP or forward : next
if (code==33 || code== 37) document.location = "slide.xql?{$uri};{$prev}" //Page Down or back : previous
if (code==66 || code==38 ) document.location = "slide.xql?{$uri};0" //b or up : index
if (code==36) document.location ="slide.xql?{$uri};1" //Home : first
if (code==35) document.location ="slide.xql?{$uri};{$count}" //End : last
if (code==80 || code==40 ) document.location ="slide.xql?{$uri};0;print" //p : print
}}
</script>
};
Generate
[edit | edit source]declare option exist:serialize "method=xhtml media-type=text/html";
if ($mode="slide")
then
<html>
<head>
<title>{string($slideshow/ss:title)} - Slides</title>
<link rel="stylesheet" type="text/css" href="{$slideshow/ss:css/ss:slide}"/>
{local:keypress-script()}
</head>
<body onkeydown="keypress(event)">
{ if ($n=0)
then local:show-contents()
else local:show-slide($slides[$n])
}
</body>
</html>
else ...
Print format
[edit | edit source]Other functions generate a printable version of the slide show. This comprises :
Contents Page
[edit | edit source]declare function local:print-contents() as element(div) {
<div class="contents">
<h2>Contents</h2>
<ul>
{for $slide at $i in $slides
return
<li>{$i} . <a href="slide.xql?{$uri};{$i}">{string($slide/h:h1)}</a> </li>
}
</ul>
</div>
};
Slides
[edit | edit source]declare function local:print-slides() as element(div)* {
for $slide at $i in $slides
return
$slide
};
Links
[edit | edit source]The URIs for links is not visible in the printed slides, so it is useful to add a final page with all the links which appear in the slides listed together.
declare function local:print-links() as element(div) {
<div class="links">
<h1>Links</h1>
<ul>
{for $slide at $i in $slides
for $link in $slide//h:a
order by upper-case($link)
return
<li>{string($link)} :<em>{string($link/@href)}</em> </li>
}
</ul>
</div>
};
Generate Print View
[edit | edit source]If the mode is "print" then generate the print format:
..
else
<html>
<head>
<title>{string($slideshow/ss:title)} - Print</title>
<link rel="stylesheet" type="text/css" href="{$slideshow/ss:css/ss:print}"/>
</head>
<body>
{local:print-contents()}
{local:print-slides()}
{local:print-links()}
</body>
</html>
Execute
[edit | edit source]- An introductory lecture - incomplete CW 18/09/08