Wednesday, November 15, 2006

I just thought it would be more sense to provide a link to the files mentioned in my last post.  Grab them if you are interested.

Wednesday, November 15, 2006 8:45:46 AM (AUS Eastern Standard Time, UTC+10:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, November 13, 2006

I've hacked on a little bit about XSLT and I think it's about time I added some more.  So this post will serve as the next instalment, and somewhat of an introduction to the uninitiated.

Lets say we were to consider the following data:

Position Horse Jockey
1 Delta Blues (JPN) Y. Iwata
2 Pop Rock (JPN) D. Oliver
3 Maybe Better (AUS) C. Munce
4 Zipping (AUS) G. Boss
5 Land 'n Stars (GB) J. Egan
6 Mahtoum (AUS) C. Brown
7 Yeats (IRE) K. Fallon
8 Activation (NZ) M. Rodd
9 Mandela (NZ) C. Williams
10 Glistening (GB) S. Seamer

As XML, it could concievably arrive like this:

<raceResults>
<finish result="1" jockey="Y. Iwata" originISO="JPN">Delta Blues</finish>
<finish result="2" jockey="D. Oliver" originISO="JPN">Pop Rock</finish>
<finish result="3" jockey="C. Munce" originISO="AUS">Maybe Better</finish>
<finish result="4" jockey="G. Boss" originISO="AUS">Zipping</finish>
<finish result="5" jockey="J. Egan" originISO="GB">Land 'n Stars</finish>
<finish result="6" jockey="C. Brown" originISO="AUS">Mahtoum</finish>
<finish result="7" jockey="K. Fallon" originISO="IRE">Yeats</finish>
<finish result="8" jockey="M. Rodd" originISO="NZ">Activation</finish>
<finish result="9" jockey="C. Williams" originISO="NZ">Mandela</finish>
<finish result="10" jockey="S. Seamer" originISO="GB">Glistening</finish>
</raceResults>

And that is fine, and may well even be useful.  The place where we should introduce XSLT is when we would like to do something with it like turning that XML into text, HTML, or more XML.

Text is an easy one to start with.  Consider the following stylesheet:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text"/>

<xsl:template match="/">
   <xsl:apply-templates select="raceResults"/>
</xsl:template>

<xsl:template match="raceResults">
position,jockey,horse,
<xsl:apply-templates select="finish"/>
</xsl:template>

<xsl:template match="finish">
   <xsl:value-of select="@result"/>,<xsl:value-of select="@jockey"/>,<xsl:value-of select="."/>,
</xsl:template>

</xsl:stylesheet>

When applied to our XML, it will produce the following result:

position,jockey,horse,
1,Y. Iwata,Delta Blues,
2,D. Oliver,Pop Rock,
3,C. Munce,Maybe Better,
4,G. Boss,Zipping,
5,J. Egan,Land 'n Stars,
6,C. Brown,Mahtoum,
7,K. Fallon,Yeats,
8,M. Rodd,Activation,
9,C. Williams,Mandela,
10,S. Seamer,Glistening,

The trick is first to not look for flow control in the traditional fashion (For loops, etc).  Instead the XSLT processor will treat it in the following manner:

  1. Start at the top of the source document - denoted with a /
  2. Every time you find a raceResults do what is in the raceResults template.
  3. (now inside the raceResults template) output the literal string: position,jockey,horse,
  4. (still inside the raceResults template) every time you find a finish, do what is in the finish template
  5. (now inside the finish template) Pick out the attribute called result, then pick out the attribute called jockey, then pick out what ever is contained in this element.  NB:  Attributes are denoted by the @

And that is it!

Now did you notice how literal text was handled?  All the bits of your output can live inside the template.  Now if we wanted an HTML representation we would use the following template:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html"/>

<xsl:template match="/">
   <html><head><title>Race Results</title></head><body>
   <xsl:apply-templates select="raceResults"/>
   </body></html>
</xsl:template>

<xsl:template match="raceResults">
<xsl:apply-templates select="finish"/>
</xsl:template>

<xsl:template match="finish">
   <p>Position <b><xsl:value-of select="@result"/></b>was <b><xsl:value-of select="."/></b>ridden by <b><xsl:value-of select="@jockey"/></b></p>
</xsl:template>

</xsl:stylesheet>

...and following exactly the same steps as the text example, the XSLT processor will output the following HTML:

Position 1 was Delta Blues ridden by Y. Iwata

Position 2 was Pop Rock ridden by D. Oliver

Position 3 was Maybe Better ridden by C. Munce

Position 4 was Zipping ridden by G. Boss

Position 5 was Land 'n Stars ridden by J. Egan

Position 6 was Mahtoum ridden by C. Brown

Position 7 was Yeats ridden by K. Fallon

Position 8 was Activation ridden by M. Rodd

Position 9 was Mandela ridden by C. Williams

Position 10 was Glistening ridden by S. Seamer

As you can imagine, it can be easy to get a stylesheet for HTML output that contains a lot of HTML markup!  The important thing to note in this example is that the HTML inside the stylesheet must be valid XML as well as valid HTML.  Note the closing </p> which would normally be optional in HTML is manditory here.

Now we get to the fun example:  Turning XML into XML :D

Why would we want to turn XML into XML?  For as many reasons as you have XML in your life!  Imagine turning the above document into its own RSS feed for example.

We could use the following template:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes"/>

<xsl:template match="/">

<rss version="2.0">
   <channel>
      <title>Race News</title>
      <link>http://www.horses.com/</link>
      <description>Live race results as they cross the finish line.</description>
      <language>en-us</language>
      <pubDate>Tue, 13 Nov 2006 17:45:00 AEST</pubDate>
      <lastBuildDate>Tue, 13 Nov 2006 17:45:00 AEST</lastBuildDate>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs>
      <generator>My RSS transformation</generator>
      <managingEditor>james@deepdark.net</managingEditor>
      <webMaster>james@deepdark.net</webMaster>
     
   <xsl:apply-templates select="raceResults"/>
  
   </channel>
</rss>

</xsl:template>

<xsl:template match="raceResults">
<xsl:apply-templates select="finish"/>
</xsl:template>

<xsl:template match="finish">
      <item>
         <title><xsl:value-of select="."/></title>
         <link>http://www.horses.com/lookup?<xsl:value-of select="."/></link>
         <description>Registered in: <xsl:value-of select="@originISO"/> .  Ridden by: <xsl:value-of select="@jockey"/></description>
         <pubDate>Tue, 13 Nov 2006 17:45:00 AEST</pubDate>
         <guid>http://www.horses.com/results/race6273-<xsl:value-of select="@result"/></guid>
      </item>
</xsl:template>
</xsl:stylesheet>

This example is the reason I took you so far down the page.  It builds on the key points of the prior two examples: 

  1. The output can mingle in stylesheet, so long as it is valid XML.  I hope you have noticed that the stylesheet itself is valid XML too.
  2. Again there are no flow control pieces.  In fact is is using exactly the same 5 step process I outlined for the first example (you guessed it, this was no mistake :)

The output is the following lovely RSS feed:

<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>Race News</title>
<link>http://www.horses.com/</link>
<description>Live race results as they cross the finish line.</description>
<language>en-us</language>
<pubDate>Tue, 13 Nov 2006 17:45:00 AEST</pubDate>
<lastBuildDate>Tue, 13 Nov 2006 17:45:00 AEST</lastBuildDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<generator>My RSS transformation</generator>
<managingEditor>james@deepdark.net</managingEditor>
<webMaster>james@deepdark.net</webMaster>
<item>
<title>Delta Blues</title>
<link>http://www.horses.com/lookup?Delta Blues</link>
<description>Registered in: JPN .  Ridden by: Y. Iwata</description>
<pubDate>Tue, 13 Nov 2006 17:45:00 AEST</pubDate>
<guid>http://www.horses.com/results/race6273-1</guid>
</item>
<item>
<title>Pop Rock</title>
<link>http://www.horses.com/lookup?Pop Rock</link>
<description>Registered in: JPN .  Ridden by: D. Oliver</description>
<pubDate>Tue, 13 Nov 2006 17:45:00 AEST</pubDate>
<guid>http://www.horses.com/results/race6273-2</guid>
</item>
<item>
<title>Maybe Better</title>
<link>http://www.horses.com/lookup?Maybe Better</link>
<description>Registered in: AUS .  Ridden by: C. Munce</description>
<pubDate>Tue, 13 Nov 2006 17:45:00 AEST</pubDate>
<guid>http://www.horses.com/results/race6273-3</guid>
</item>
<item>
<title>Zipping</title>
<link>http://www.horses.com/lookup?Zipping</link>
<description>Registered in: AUS .  Ridden by: G. Boss</description>
<pubDate>Tue, 13 Nov 2006 17:45:00 AEST</pubDate>
<guid>http://www.horses.com/results/race6273-4</guid>
</item>
<item>
<title>Land 'n Stars</title>
<link>http://www.horses.com/lookup?Land 'n Stars</link>
<description>Registered in: GB .  Ridden by: J. Egan</description>
<pubDate>Tue, 13 Nov 2006 17:45:00 AEST</pubDate>
<guid>http://www.horses.com/results/race6273-5</guid>
</item>
<item>
<title>Mahtoum</title>
<link>http://www.horses.com/lookup?Mahtoum</link>
<description>Registered in: AUS .  Ridden by: C. Brown</description>
<pubDate>Tue, 13 Nov 2006 17:45:00 AEST</pubDate>
<guid>http://www.horses.com/results/race6273-6</guid>
</item>
<item>
<title>Yeats</title>
<link>http://www.horses.com/lookup?Yeats</link>
<description>Registered in: IRE .  Ridden by: K. Fallon</description>
<pubDate>Tue, 13 Nov 2006 17:45:00 AEST</pubDate>
<guid>http://www.horses.com/results/race6273-7</guid>
</item>
<item>
<title>Activation</title>
<link>http://www.horses.com/lookup?Activation</link>
<description>Registered in: NZ .  Ridden by: M. Rodd</description>
<pubDate>Tue, 13 Nov 2006 17:45:00 AEST</pubDate>
<guid>http://www.horses.com/results/race6273-8</guid>
</item>
<item>
<title>Mandela</title>
<link>http://www.horses.com/lookup?Mandela</link>
<description>Registered in: NZ .  Ridden by: C. Williams</description>
<pubDate>Tue, 13 Nov 2006 17:45:00 AEST</pubDate>
<guid>http://www.horses.com/results/race6273-9</guid>
</item>
<item>
<title>Glistening</title>
<link>http://www.horses.com/lookup?Glistening</link>
<description>Registered in: GB .  Ridden by: S. Seamer</description>
<pubDate>Tue, 13 Nov 2006 17:45:00 AEST</pubDate>
<guid>http://www.horses.com/results/race6273-10</guid>
</item>
</channel>
</rss>

I think this technique is going to be ever more important in the future.  Take in some SOAP, spit out some HTML.  Take in some XML from one API, spit it out as RSS.  A great tool for the toolbox.

Monday, November 13, 2006 6:22:02 PM (AUS Eastern Standard Time, UTC+10:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, November 07, 2006
So here is what I want from the perfect laptop.
  • 15 inch widescreen capable of 1600x1000 - good for coding.
  • Weigh no more than 2Kg
  • All the standard bits like WiFi, a Windows key & better support for Suspend than my aging Inspiron 1100.  I wanna be like a mac guy and just shut the lid of the machine and not worry about it.  With my Inspiron that would cause a fire.
  • 100Gb SATA HDD, 2Gb RAM, Dual Core, Vista Ready
  • Definately less than AUD$3000, closer to $2000 the better
Here's the kicker:  Convertable tablet form factor and it kicks the res down to 1125x864, or 1024x768 when flipped for tablet-like note taking and ad-hoc jotting.

One day I'm gonna be looking back on this post on such a machine and grin :)

Tuesday, November 07, 2006 5:41:08 PM (AUS Eastern Standard Time, UTC+10:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, November 06, 2006
Its been a little while since my last Language Nerd post, so...

Rory Blyth has had a seriously cool and often unhinged blog for quite some time now.  He's tapping into the wealth of his best blog posts for his new podcast, The Smartest Man In the World

He really is an imaginative and original writer.  Go check it out ;)

Monday, November 06, 2006 12:53:11 PM (AUS Eastern Standard Time, UTC+10:00)  #    Disclaimer  |  Comments [0]  | 
Monday, November 06, 2006 12:34:22 PM (AUS Eastern Standard Time, UTC+10:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, November 01, 2006
I love it when things come together:
CodeRush and Refactor! - I'm a fan
I love a good keyboard too.

Here's a nice little plugin for Refactor! that can show available refactorings or metrics on the display of a Logitech G15.  Too cool!

Wednesday, November 01, 2006 5:33:20 PM (AUS Eastern Standard Time, UTC+10:00)  #    Disclaimer  |  Comments [0]  | 
I thought it was about time I refreshed my rules for what good error messages are:

  • Consistant.  This could be visually consistant in the case of message boxes, or if they are being logged to a file or database table then being consistant helps them also to be machine readable.
  • Informative.  Consider ADO & ADO.Net's old "General Network Error" as the best example of how not to do errors.  The key point here is the message should first say:
  1. what did not work correctly, and
  2. what you should do next to fix it
Stack traces etc should come later.
  • Appropriate.  Consider the audience of your application.  They are the audience for your erorrs too!  The level of detail I expect in an error from SQL Server is completely different to the kind error I expect from iTunes. 
  • Respect my attention span.  750 Event Log messages a day means I won't look at them.  Once a quater means I won't look at them.  The latter case should be emailed.  The former case probabbly should be replaced with one critical failure message :-)
  • Respect my privacy.  Passwords, maybe even user names, or anything that is sensative in the context of the application should not apear in an error message.  I don't have a convienient example of one with a password in it (maybe check a more complete source) but this would probabbly also extend to stack traces.
This is a growing list.  It gets revised when I see something done well, or something done poorly (or when I do something well, or when I do something poorly.  Now I've blogged it.

It started out with just the Informative rule, motivated by the cost of the support desk having to get involved in a support issue vs. the user working it out for themselves.

More formally, we could look at an error with the following criteria:
  • What does this message do for the user experience?
  • What does this message do to avoid the user having to call someone?


Wednesday, November 01, 2006 5:22:55 PM (AUS Eastern Standard Time, UTC+10:00)  #    Disclaimer  |  Comments [1]  | 
 Monday, October 30, 2006
Monday, October 30, 2006 9:17:15 PM (AUS Eastern Standard Time, UTC+10:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, October 18, 2006
So I've just worked it out...

If you want to edit a list in Datasheet View - an insanely useful feature - you must not have Office Basic or Office Small Business versions.

You have to have the Pro version of Office and make sure the "Microsoft Office List Datasheet Component" is installed in the "Office Tools\Windows SharePoint Services Support" option in selected as Installed under Office setup.


Wednesday, October 18, 2006 5:59:38 PM (AUS Eastern Standard Time, UTC+10:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, October 16, 2006
To the end of making my unit tests as easy to write as possible, I thought the default CodeRush template for adding a new NUNit Test Fixture to my projects could do with some tweeking, or at least customization.  Here's how I like mine:

<TestFixture> _
Public Class «Caret»«Field(ClassTests)»«BlockAnchor»
    
<Test> _
    Public Sub «Field(MethodTest)»()
        «Marker»
    End Sub
End Class

My next question is, how can I make the ClassTests field default to the name of the file?

After blog mint [?]:  There are extra fields that you can insert into the template expansion, these are Text Commands and String Providers.  You get to these by right-clicking the Expansion area and choosing Text Commands or String Providers and selecting from the list.  The FileName string provider might be just what I need.

Monday, October 16, 2006 9:30:34 AM (AUS Eastern Standard Time, UTC+10:00)  #    Disclaimer  |  Comments [0]  |