Monday, March 31, 2008

Daylight savings considered evil

I don't really care when we do daylight savings in my day to day life. In my work life, however, I really do.

If it's not broken, don't mess with it.

Unfortunately, South Australia (where our servers are) decided to move the standard end date of daylight savings time by a week. Just for this year as far as I know.

This was not very well publicised here. Nor did it enable business to get their systems up to date.

This now means our server's PHP is broken, mysql is upset, PEAR::Date is upset and it has to stay that way for a week.

What a %#^#%ing mess.

Sunday, March 30, 2008

PEAR installation process

PEAR needs to think about its usability for newcomers.

Who are our audience?


I would say they fit into several broad categories.

First, the web designer who is learning PHP.
This person isn't used to anything much more than javascript, has lots of basic php language questions, and wants to do possibly nasty things with the language.

Second, the system administrator - this person knows just enough php to know they don't want to know anymore, relies on a range of tools - from cpanel to phpmyadmin.
They are setting up a shared environment, typically. They just want results, and they want them fairly quickly.

Third, the just setting out as a seasoned developer. This person is working in PHP5, and is half a heartbeat away from leaping on the rails-bandwagon. They are looking for frameworks, quick code and things which are visually fun. They are usually working as a full time developer.

Fourth, the ultra seasoned developer. This person is working in PHP5, has a background in Java or other languages, and wants to Do The Right Thing. They are usually working as a full time developer - they use unit tests, design patterns, and are often willing to provide patches.

Probably categories three and four overlap markedly.

Scenarios


Ultra seasoned developer has a specific design problem - database abstraction


The last 3 projects they have worked on have used the mysql extension, ADODB, and others.

They type in 'database abstraction php'; and among the results is PEAR::DB.

The first few links are newbie tutorials, and thus skipped.

When viewing the PEAR::DB homepage, they note it is unmaintained, and MDB2 should be used.

Wanting to know more, they click into the documentation, and read the end user docs.

From here, they see a few samples of code.

Convinced to at least try it out, they then turn to install it.

Newbie has been told to RTFM and learn about PEAR


Using newfound google prowess, the newbie discovers pear. They have been told to go and read the manual about mail(), and want to know how to send attachments.

They land at http://pear.php.net/ and click around a little bit.

They eventually discover the Packages section.

Here, they eventually find a package they want - PEAR::Mail.

They get to the package homepage.

They hit the download button, and are given a .tar.gz - being mostly a windows user, this stumps them.

A system admin at a small web hosting company has had a user complain that fictionalbb doesn't work: it has some error about HTML/QuickForm.php


The system admin pastes the error message into google, and lands on a forum post.

The forum post tells them they need to install HTML_QuickForm, and it's this thing called a PEAR package.

They land on pear.php.net. They give up after a short period, as there doesn't appear to be anything useful.

Instead, they type 'ubuntu html_quickform howto' or 'redhat fictionalbb install' into google.

Somewhere, they locate a forum post, which eventually leads them to the right answer.

How can we make these user stories better?


First, when you land on the front page, there should be a clear direction.

landing-branding

Ask the user what they are trying to accomplish, and direct them to the resources they need.


Second, make the package download page more useful.
download
If you have no idea how to install pear, you are going to end up trying to download.

This page should provide you with more direction, and links to 'installing pear'



Third, when they land on the package documentation page, give them an instant teaser.

documentation

Show the table of contents right there and then, rather than hide it away.

Provide a spot for useful external articles to make the selling process better.

If the user can read and understand right there and then, they'll be happier.

Digg and XHTML

If you use Digg I bet you are sick of XHTML / CSS articles.

The thing which annoys me most is the available addons for firefox just aren't used.

Just look at the front page of digg: 66 errors / 13 warnings.

And the first one to come up - a typo.

line 35 column 804 - Error: there is no attribute "valie"
line 35 column 819 - Error: there is no attribute "tab-index"
line 35 column 874 - Error: end tag for element "button" which is not open
line 40 column 37 - Warning: cannot generate system identifier for general entity "PG"
line 40 column 37 - Error: general entity "PG" not defined and no default entity
line 40 column 39 - Error: reference to entity "PG" for which no system identifier could be generated
line 40 column 36 - Info: entity was defined here
line 40 column 47 - Warning: cannot generate system identifier for general entity "AP"
line 40 column 47 - Error: general entity "AP" not defined and no default entity
line 40 column 49 - Error: reference to entity "AP" for which no system identifier could be generated
line 40 column 46 - Info: entity was defined here
line 40 column 55 - Warning: cannot generate system identifier for general entity "PN"
line 40 column 55 - Error: general entity "PN" not defined and no default entity
line 40 column 57 - Error: reference to entity "PN" for which no system identifier could be generated
line 40 column 54 - Info: entity was defined here
line 43 column 81 - Warning: cannot generate system identifier for general entity "topics"
line 43 column 81 - Error: general entity "topics" not defined and no default entity
line 43 column 87 - Error: reference to entity "topics" for which no system identifier could be generated
line 43 column 80 - Info: entity was defined here
line 43 column 272 - Warning: cannot generate system identifier for general entity "media"
line 43 column 272 - Error: general entity "media" not defined and no default entity
line 43 column 277 - Error: reference to entity "media" for which no system identifier could be generated
line 43 column 271 - Info: entity was defined here
line 44 column 61 - Error: reference to entity "topics" for which no system identifier could be generated
line 43 column 80 - Info: entity was defined here
line 44 column 251 - Error: reference to entity "media" for which no system identifier could be generated
line 43 column 271 - Info: entity was defined here
line 45 column 62 - Error: reference to entity "topics" for which no system identifier could be generated
line 43 column 80 - Info: entity was defined here
line 45 column 252 - Error: reference to entity "media" for which no system identifier could be generated
line 43 column 271 - Info: entity was defined here
line 46 column 62 - Error: reference to entity "topics" for which no system identifier could be generated
line 43 column 80 - Info: entity was defined here
line 46 column 252 - Error: reference to entity "media" for which no system identifier could be generated
line 43 column 271 - Info: entity was defined here
line 50 column 176 - Warning: cannot generate system identifier for general entity "eurl"
line 50 column 176 - Error: general entity "eurl" not defined and no default entity
line 50 column 180 - Error: reference to entity "eurl" for which no system identifier could be generated
line 50 column 175 - Info: entity was defined here
line 50 column 1988 - Warning: cannot generate system identifier for general entity "thread.id"
line 50 column 1988 - Error: general entity "thread.id" not defined and no default entity
line 50 column 1997 - Error: reference to entity "thread.id" for which no system identifier could be generated
line 50 column 1987 - Info: entity was defined here
line 50 column 2005 - Warning: cannot generate system identifier for general entity "view"
line 50 column 2005 - Error: general entity "view" not defined and no default entity
line 50 column 2009 - Error: reference to entity "view" for which no system identifier could be generated
line 50 column 2004 - Info: entity was defined here
line 50 column 2028 - Warning: cannot generate system identifier for general entity "page"
line 50 column 2028 - Error: general entity "page" not defined and no default entity
line 50 column 2032 - Error: reference to entity "page" for which no system identifier could be generated
line 50 column 2027 - Info: entity was defined here
line 59 column 77 - Warning: cannot generate system identifier for general entity "source"
line 59 column 77 - Error: general entity "source" not defined and no default entity
line 59 column 83 - Error: reference to entity "source" for which no system identifier could be generated
line 59 column 76 - Info: entity was defined here
line 66 column 86 - Error: reference to entity "source" for which no system identifier could be generated
line 59 column 76 - Info: entity was defined here
line 69 column 85 - Error: reference to entity "source" for which no system identifier could be generated
line 59 column 76 - Info: entity was defined here
line 71 column 54 - Warning: cannot generate system identifier for general entity "lpos"
line 71 column 54 - Error: general entity "lpos" not defined and no default entity
line 71 column 58 - Error: reference to entity "lpos" for which no system identifier could be generated
line 71 column 53 - Info: entity was defined here
line 74 column 41 - Error: reference to entity "PG" for which no system identifier could be generated
line 40 column 36 - Info: entity was defined here
line 74 column 51 - Error: reference to entity "AP" for which no system identifier could be generated
line 40 column 46 - Info: entity was defined here
line 74 column 57 - Warning: cannot generate system identifier for general entity "SEG"
line 74 column 57 - Error: general entity "SEG" not defined and no default entity
line 74 column 60 - Error: reference to entity "SEG" for which no system identifier could be generated
line 74 column 56 - Info: entity was defined here
line 85 column 68 - Error: there is no attribute "about"
line 87 column 112 - Error: there is no attribute "property"
line 89 column 16 - Error: there is no attribute "property"
line 99 column 45 - Error: there is no attribute "content"
line 110 column 31 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 133 column 31 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 133 column 96 - Warning: cannot generate system identifier for general entity "sid"
line 133 column 96 - Error: general entity "sid" not defined and no default entity
line 133 column 99 - Error: reference to entity "sid" for which no system identifier could be generated
line 133 column 95 - Info: entity was defined here
line 156 column 31 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 179 column 31 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 202 column 31 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 225 column 31 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 249 column 12 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 276 column 12 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 302 column 31 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 326 column 12 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 356 column 31 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 356 column 133 - Error: reference to entity "thread.id" for which no system identifier could be generated
line 50 column 1987 - Info: entity was defined here
line 356 column 145 - Error: reference to entity "view" for which no system identifier could be generated
line 50 column 2004 - Info: entity was defined here
line 356 column 168 - Error: reference to entity "page" for which no system identifier could be generated
line 50 column 2027 - Info: entity was defined here
line 379 column 31 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 379 column 115 - Warning: cannot generate system identifier for general entity "loomia_si"
line 379 column 115 - Error: general entity "loomia_si" not defined and no default entity
line 379 column 124 - Error: reference to entity "loomia_si" for which no system identifier could be generated
line 379 column 114 - Info: entity was defined here
line 402 column 31 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 425 column 31 - Error: ID "title0" already defined
line 87 column 31 - Info: ID "title0" first defined here
line 476 column 124 - Error: reference to entity "source" for which no system identifier could be generated
line 59 column 76 - Info: entity was defined here
line 521 column 35 - Error: end tag for "ul" which is not finished
line 526 column 37 - Error: end tag for "ul" which is not finished
line 530 column 39 - Error: end tag for "ul" which is not finished
line 539 column 6 - Error: end tag for "div" omitted, but OMITTAG NO was specified
line 35 - Info: start tag was here


If I can do it:

Result: 0 errors / 10 warnings

line 4 column 5 - Warning: <head> escaping malformed URI reference
line 235 column 11 - Warning: <iframe> attribute "height" has invalid value "30px"
line 248 column 29 - Warning: <a> cannot copy name attribute to id
line 289 column 29 - Warning: <a> cannot copy name attribute to id
line 330 column 29 - Warning: <a> cannot copy name attribute to id
line 371 column 29 - Warning: <a> cannot copy name attribute to id
line 412 column 29 - Warning: <a> cannot copy name attribute to id
line 451 column 29 - Warning: <a> cannot copy name attribute to id
line 492 column 29 - Warning: <a> cannot copy name attribute to id
line 533 column 29 - Warning: <a> cannot copy name attribute to id
Info: Doctype given is "-//W3C//DTD XHTML 1.0 Transitional//EN"
Info: Document content looks like XHTML 1.0 Transitional

... so can they

Tuesday, March 25, 2008

Unsupported by IE7/8: textContent()

IE 8 doesn't implement textContent.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Broken textContent()</title>
</head>

<body>
<p id="textcontent">
It's called textContent()
Got any?
</p>
<script type="text/javascript">
alert(document.getElementById('textcontent').textContent);
alert(document.getElementById('textcontent').innerHTML);
</script>
</body>
</html>

Sunday, March 23, 2008

How to make OpenID really rock (user signup process)

Robby finds himself asking why come I have 75 openids, and why can't I just transfer my details from site to site?

Well Robby, this is for you.


First, you need to grab XML_GRDDL. It's fairly stable at the moment, and a PEPR proposal.

For now, do a

pear install http://xmlgrddl.googlecode.com/files/XML_GRDDL-0.0.4.tgz

... but if it gets through PEPR, this will be easier.


Be warned, you'll need version of PHP 5.2.5+ unless you can compile php with a decent version of libxml / libxslt.

You also need the XSL extension.

Open up your favourite editor.

Paste in:

require_once 'XML/GRDDL.php';

/**
* Example: Fetch multiple URLs about a specific user
* and get useful information out.
*/
$urls = array();
$urls[0] = 'http://flickr.com/people/clockwerx/';
$urls[1] = 'http://www.linkedin.com/in/clockwerx';
$urls[2] = 'http://www.last.fm/user/CloCkWeRX/';
$urls[3] = 'http://clockwerx.blogspot.com/';

//For each URL, pretend it has these urls in <head profile="foo" />
//These look for hcard, hcalendar, etc.
$profiles[$urls[0]][] = 'http://www.w3.org/2002/12/cal/cardcaletc';
$profiles[$urls[1]][] = 'http://microformats.org/wiki/hresume-profile';
$profiles[$urls[1]][] = 'http://www.w3.org/2002/12/cal/cardcaletc';
$profiles[$urls[2]][] = 'http://www.w3.org/2002/12/cal/cardcaletc';
$profiles[$urls[3]][] = 'http://www.w3.org/2002/12/cal/cardcaletc';

//Set what kind of transformations we're interested in.


$options = XML_GRDDL::getDefaultOptions();
$options['quiet'] = true;

$grddl = XML_GRDDL::factory('xsl', $options);
$results = array();
foreach ($urls as $n => $url) {
$data = $grddl->fetch($url);

$data = $grddl->prettify($data);

$modified_data = $grddl->appendProfiles($data, $profiles[$url]);

$stylesheets = $grddl->inspect($modified_data, $url);

$rdf_xml = array();
foreach ($stylesheets as $stylesheet) {
$rdf_xml[] = $grddl->transform($stylesheet, $modified_data);
}

$results[$url] = array_reduce($rdf_xml, array($grddl, 'merge'));
}

print "We scuttered " . count($urls) . " urls and found these results\n";
foreach ($results as $url => $rdf_xml) {
print $url . "\n";

$sxe = simplexml_load_string($rdf_xml);
$sxe->registerXPathNamespace('vcard', 'http://www.w3.org/2006/vcard/ns#');
$sxe->registerXPathNamespace('ical', 'http://www.w3.org/2002/12/cal/icaltzd#');

print "We found the following pieces of information, choose which are yours:\n";
$xpaths = array();
$xpaths["Formatted name"] = '//vcard:fn';
$xpaths["First name"] = '//vcard:givenName';
$xpaths["Last name"] = '//vcard:familyName';
$xpaths["Email"] = '//vcard:email';
$xpaths["Homepage or URl"] = '//vcard:url';
$xpaths["Workplace name"] = '//vcard:organization-name';
$xpaths["Photo URL"] = '//vcard:photo';
$xpaths["Locality"] = '//vcard:locality';
$xpaths["Position/Title"] = '//vcard:title';

foreach ($xpaths as $name => $xpath) {
$results = $sxe->xpath($xpath);
if (empty($results)) {
continue;
}

print $name . ": ";
foreach ($results as $node) {
print trim((string)$node);
$attributes = $node->attributes(XML_GRDDL::RDF_NS);
if (!empty($attributes['resource'])) {
print trim((string)$attributes['resource']);
}
print "\n";
}
}
//print $rdf_xml . "\n\n";
print "\n";
}


Save it, run it.

You *should get*:

---------- PHP ----------
We scuttered 4 urls and found these results
http://flickr.com/people/clockwerx/
We found the following pieces of information, choose which are yours:
Formatted name: DanielO'Connor
First name: Daniel
Last name: O'Connor
Homepage or URl: http://clockwerx.blogspot.com/
Locality: Klemzig
Position/Title: Web Developer

http://www.linkedin.com/in/clockwerx
We found the following pieces of information, choose which are yours:
Formatted name: Daniel
O'Connor
Adelaide Institude of TAFE
PEAR member
LIXI Members member
First name: Daniel
Last name: O'Connor
Homepage or URl: http://http;//clockwerx.blogspot.com
http://www.valuationexchange.com.au
Workplace name: PEAR
Valuation Exchange
Fresh FM
Self-employed
Adelaide Institude of TAFE
PEAR member
LIXI Members member
Locality: Adelaide Area, Australia
Position/Title: Developer at Valuation Exchange
Contributer
Software Developer
Web Developer
Freelancer

http://www.last.fm/user/CloCkWeRX/
We found the following pieces of information, choose which are yours:
Formatted name: Daniel O'Connor
NoBloodForOil
Homepage or URl: http://clockwerx.blogspot.com
Photo URL: http://userserve-ak.last.fm/serve/160/682792.jpg
http://userserve-ak.last.fm/serve/50/690470.gif

http://clockwerx.blogspot.com/
We found the following pieces of information, choose which are yours:
Formatted name: Daniel O'Connor
Email: mailto:daniel.oconnor@gmail.com
Homepage or URL: http://clockwerx.blogspot.com/
xmpp:daniel.oconnor@gmail.com
Workplace name: Valuation Exchange


Output completed (30 sec consumed)


Now, how neat is that. You can grab any url which publishes microformats, grab out the hcards from it, grab the information from those, and viola! A pre-populated signup form.


Why is this neat?
* If an OpenID url has Microformats, bam! You can read it.
* If you are a bit more hardcore, you can hook up xOperator and a triplestore to this information.
* Or you could use it in Drupal.

There you have it, ladies and gents: semantic web in a box, with practical applications for user signup.

Saturday, March 22, 2008

Systembot - Ready or Not

Systembot are awesome.

So is their track, ready or not (MP3).

If you don't know them, you are missing out.

Check out the website, or grab the album, Fuse via paypal.

Friday, March 21, 2008

User Experience with Bugtracking in PHP

I am sick of reporting bugs which get marked as bogus.

Who chose bogus as a label? Why? What were they thinking?

"Hi! I see you care enough to report a problem with our product. We've taken a closer look, and here's our answer: this is bogus."

This seems to be only the PHP bugtracker where this happens, and where it makes me foam at the mouth.

I don't have experiences like this in other bugtrackers/communities, including BMO, Trac, Rails and PEAR.


I think the worst thing about all of this is when I report a bug like 44489.

I have:
  • Read the manual
  • Used the same code as the example code in the manual
  • Used it successfully in at least 20 other cases
  • Received an error PHP Warning: XSLTProcessor::importStylesheet(): compilation error:
    file http://www.w3.org/2001/sw/grddl-wg/td/hl7-rim-to-pomr.xslt line 179
    element type
  • Verified it works with xsltproc
  • Visually inspected the xsl to see if there is anything obvious


and I get an answer of:


You need to load stylesheets with proper flags:
$xsl->load('http://www.w3.org/2001/sw/grddl-wg/td/hl7-rim-to-pomr.xslt', LIBXML_NOCDATA|LIBXML_NOENT);


WHERE IS THAT DOCUMENTED?!

ARGH!


Now this is not rrichard's fault at all, he's putting in the time and effort to actually solve my problems; but the tools and the default responses he gets shifted into by them are abysmal.

The correct answer here, and in many other bugs is not bogus.

It's we need more documentation, sorry this was confusing, we'll do better next time.

That way, I feel like the developers actually care that I invested the time to file the bug, and it helps identify areas of low documentation coverage.

Thursday, March 13, 2008

Fire eagle

Andrew points to Fireeagle.

It's a geotwitter, basically - applications can read and write information for "where is user X now".

This is the web 2.0 version of menow.

Neat.

Selling the Semantic Web - Diggbait

The problem with selling the semantic web stems from its academic background.

If you're hacking the semantic web together, you are:
  • About to publish a paper
  • Doing something with OWL
  • Building a triplestore
  • Building a library of some description
  • An author
  • Tim Berners Lee


To do any of these things, you need to be smart, plucky and grok lots of acronyms.

The trouble is, none of those things listed above is a "web designer", or "web developer".
If there's much connection between "web developer" and any of the above, it tends to be more of the "I'm an elite specialist who dabbles in web development".

What does that all have to do with selling the semantic web?
It means that most of us don't make good diggbait.

Here's an experiment:
Use google to find a tutorial on implementing small parts of the semantic web, suitable for someone who knows a little PHP or RoR.

What do we have:
Semantic Web howto - currently broken XML.
Triplestore tutorial - Links to Prolog pages! ARGH! RUN!
Also: a python rdflib article - better, but this gets into RDF/XML very quickly, and I'm not sold on the benefits.
virtuoso tutorial - nada.
triplestore hosting - a broken blog post link.
microformats tutorial - where's the GRDDL / RDFa stuff!

I think you'll begin to see a pattern. We don't write compelling, bite size stuff!

My 8 second web 2.0 mind can't comprehend half of the results, so I end up moving onto stuff like "Man is eaten by Bear/New AJAX Library/Ron Paul".

Think back: how did you get sold on the semantic web? For me, I read some early writing by timbl.

I was sold on a scenario: what if your email client could book you in at the hair dresser in a town you've never visited. The semantic web helps you do this (or similar).

But since that time, I've barely even played with SPARQL enough to know it fluently.

What's going on? How did this come to be?
... and the only thing I can think of is; I never hit a landing page like this.

Virtuoso landing page mockup

at least, until I started playing with GRDDL:
GRDDL

Tuesday, March 11, 2008

Microformats vs Machines

I've been toiling away in the background for a few weeks now, slowly pushing XML_GRDDL through its paces, and the GRDDL spec tests.

It's finally at a point I'm mostly happy with - it fails some xml:base related tests, and doesn't like content negotiation - though it's hard to test against a misconfigured setup.

So now that I've hit a happy place, I thought I might as well do some explorations - particularly of microformats to RDF.

So, who's got real world microformats? Flickr! Upcoming! Hurray! Or maybe not quite GRDDL friendly formats.

Not even Tantek really bothers with profiles - apart from XFN.

Now I'm about stumped. How do I convince the vast majority of microformat users to look sideways at a //head[@profile] containing GRDDL friendly information?

Especially since the driving matra behind microformats is people first, machines second

Monday, March 10, 2008

A stupid OpenID question

I am only dimly aware of what openid is/how it works.

All of a sudden I've got a livejournal, blogger, and flickr openid. So how would I merge them?

For instance, I log into a foo.com via the livejournal openid to leave a comment. The next time I log in, about 3 months later, its via my blogger openid.

I'm the same person, but how do I tell foo.com that?

The only answer I really have is "OpenID + FOAF", but only livejournal and one or two others bother outputting this.

Saturday, March 08, 2008

Thursday, March 06, 2008

IE8 Beta 1: onchange for checkboxes



This test demostrates the broken onchange behaviour in IE8.0.6001.17184

Tuesday, March 04, 2008

grokSeeAlso

Here's a quick and dirty transformation which looks for //link[@rel="alternate" and @type="application/rdf+xml"]

It simply adds in an rdfs:seeAlso, but that should be enough!

Lives at SVN, see the grddl results

<?xml-stylesheet href="http://www.w3.org/StyleSheets/base.css" type="text/css"?>
<?xml-stylesheet href="http://www.w3.org/2002/02/style-xsl.css" type="text/css"?>


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:rdf ="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs ="http://www.w3.org/2000/01/rdf-schema#"
xmlns:dataview="http://www.w3.org/2003/g/data-view#"
exclude-result-prefixes="html">


<xsl:output method="xml" encoding="utf-8" indent="yes"/>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" href="http://www.w3.org/StyleSheets/base"/>
<title>Extracting alternative application/rdf+xml descriptions</title>

</head>
<body>
<h1>Extracting alternative application/rdf+xml descriptions</h1>


<p>This is a <a href="http://www.w3.org/TR/grddl">GRDDL</a> transformation that produces a list of RDF alternative descriptions from XHTML.
Each link (<code>link</code> or <code>a</code>) with a <code>rel</code> attribute whose value includes <code>alternate</code> or <code>meta</code> and <code>type</code> whose value is <code>application/rdf+xml</code> is used to identify alternative resources which describe the source document.
</p>

<p>In the following example, written in XHTML, the <code>link</code>

element is a link by HTML conventions:</p>

<pre class="example"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head profile="http://www.w3.org/2003/g/data-view">
<link rel="alternate"
href="http://danbri.org/foaf.rdf" />
...
<p>Here's a link to my other
<a rel="alternate" type="application/rdf+xml"
href="http://danbri.org/words/feed/rdf">RSS 1.0 data</a>
</pre>

<p>
This transform is based on <a href="http://www.w3.org/2003/g/glean-profile">glean-profile.xsl</a>, which is copyright, 2005-2007, W3C.
It is available for use under the terms of the
<a href="http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231">W3C Software License</a>
</p>

</body>
</html>

<xsl:template match="/">
<rdf:RDF>
<xsl:for-each select="/html:html//html:*//
html:*
[self::html:a or self::html:link]
[@href and (contains(@rel,'meta') or contains(@rel,'alternate'))
and
contains(@type,'application/rdf+xml')
]">
<rdf:Description rdf:about=''>
<rdfs:seeAlso rdf:resource="{@href}" />
</rdf:Description>
</xsl:for-each>
</rdf:RDF>
</xsl:template>

</xsl:stylesheet>

Marc Andressen on Barack Obama

Here's Marc on on Barack Obama, and he's actually met the guy.

Open Data and Buses

Since my last tangle with the buses has left me angry about open data, it's a pleasure to come across this hublog pointer to helsinki e-buses.

Follow the links and read the articles - London is spending 117 million pounds on an e-fleet of buses, all running windows and with no plans for openness. Helsinki runs linux, and barcodes bustops.

Guess which one is cheaper and more useful?