I am making all kind of tests for the chapter about multimedia of our upcoming Web 2.0 book and as it is often the case when I am writing, this is sparkling a number of strange ideas.
I was exploring the similarities between playlists, podcasts and SMIL animation when it occurred to me that it might be interesting to see what can be done with microformats.
Although the relEnclosure proposal still needs some polishing (for instance, it mentions that Atom requires a length on enclosures but do not define a way to express this length), the result would be something such as:
<div class="hfeed">
<h1>SVG en quinze points</h1>
<div class="hentry">
<h2 class="hentry-title">
<a
href="http://xmlfr.org/documentations/articles/i040130-0001/01%20-%20C'est%20base%20sur%20XML.mp3"
rel="bookmark" title="...">C'est basé sur XML</a>
</h2>
<p class="hentry-content">By <address class="vcard author fn">Antoine Quint</address> -
<abbr class="updated" title="2004-01-30T00:00:00">2004-01-30T00:00:00</abbr>
</p>
<p>[<a
href="http://xmlfr.org/documentations/articles/i040130-0001/01%20-%20C'est%20base%20sur%20XML.mp3"
rel="enclosure">download</a>] (<span class="htype">audio/mpeg</span>, <span
class="hLength">231469</span> bytes).</p>
</div>
.
.
.
</div>
I am not a microformat expert and I have been surprised to see that this document is actually much harder to write than the corresponding Atom document. It probably contains lots of errors and if you spot one of them, thanks to report it as a comment.
This is nice, but probably not what users would expect for a Web 2.0 application. For one thing, this page is static and lacking all the bells and whistles of a Web 2.0 application. For instance, we might want to use one of the techniques exposed by Mark Huckvale to play the audio in the web page itself.
For this, we would need to modify the document and entries could become:
<div class="hentry">
<h2 class="hentry-title">
<a
href="http://xmlfr.org/documentations/articles/i040130-0001/01%20-%20C'est%20base%20sur%20XML.mp3"
rel="bookmark" title="...">C'est basé sur XML</a>
</h2>
<p class="hentry-content">By
<address class="vcard author fn">Antoine Quint</address> - <abbr
class="updated" title="2004-01-30T00:00:00"
>2004-01-30T00:00:00</abbr>
</p>
<p>[<a
href="javascript:play("http://xmlfr.org/documentations/articles/i040130-0001/01%20-%20C'est%20base%20sur%20XML.mp3");"
rel="enclosure">play</a>] (<span class="htype"
>audio/mpeg</span>, <span class="hLength">231469</span> bytes).</p>
</div>
This is not very different, but the links with rel= »enclosure » have been replaced by a call to a Javascript function and this is enough to loose the semantic of the microformat since we obfuscate the enclosure’s URL.
We have thus a situation where the document that we want to server is different from the document that we want to display client side and that’s a typical use case for client side XSLT.
The trick is to write a simple transformation that makes the static page synamic:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml" xmlns:x="http://www.w3.org/1999/xhtml" version="1.0"
exclude-result-prefixes="x">
<xsl:output method="xml" encoding="UTF-8" indent="yes" cdata-section-elements="x:style x:script"/>
<xsl:strip-space elements="*"/>
<xsl:preserve-space elements="x:script x:style"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="x:head">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<style type="text/css"><![CDATA[
#player {
padding: 10px;
background-color: gray;
position:fixed;
top: 20px;
right:10px
}
] ]></style>
<script type="text/javascript"><![CDATA[
function play(surl) {
document.getElementById("player").innerHTML=
'<embed src="'+surl+'" hidden="false" autostart="true" loop="false"/>';
}
] ]></script>
</xsl:copy>
</xsl:template>
<xsl:template match="x:body">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<div id="player">A media player<br/>will pop-up here.</div>
</xsl:copy>
</xsl:template>
<xsl:template match="x:a[@rel='enclosure']/@href">
<xsl:attribute name="href">
<xsl:text>javascript:play("</xsl:text>
<xsl:value-of select="."/>
<xsl:text>");</xsl:text>
</xsl:attribute>
</xsl:template>
<xsl:template match="x:a[@rel='enclosure']/text()">
<xsl:text>play</xsl:text>
</xsl:template>
</xsl:stylesheet>
And add a xsl-stylesheet PI to the static (microformat) page:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="decorateMf.xsl" type="text/xsl"?>
<html xmlns="http://www.w3.org/1999/xhtml">
.
.
.
</html>
This is working fine for me (GNU Linux/Ubuntu, Firefox 1.5) and the mplayer plug-in nicely pops up in the player div when I click on one of the « play » links but it would require a bit of polishing to work in other browsers:
- The page crashes Opera 9.0 (I have entered a bug report and have been contacted back by their tech support who is already working on the issue).
- The XSLT output method needs to be changed to HTML to work in Internet Explorer (otherwise the result is displayed as a XML document). Furthermore, IE inserts the embed element as text in the player div and you might need to use a proper DOM method to insert the embed element as a DOM node.
[Try it!]
There are probably a number of other (easier?) solutions for the specific problem I have solved here. However, this is an interesting pattern to apply in situations where you want to serve a clean document that needs to be altered to display nicely in a browser.
XSLT has sometimes been described as a « semantic firewall » that removes the semantic of XML documents to keep only their presentation. I like to think at this technique as a semantic « anti-firewall » or « tunnel » that keeps the semantic of XML documents intact until the very last stage before it hits the browser’s rendering engine…