Archive
AJAX JavaScript Control (2012 Update)
AJAX Control lets you quickly embed AJAX controls using text, XML and XSLT in a variety of ways to your web pages. Read more…
IE7 Conditional Comments and XSL
About conditional comments
Conditional comments in Internet Explorer 7 are a way to ensure only IE or non-IE browsers parse certain parts of a page. This is mostly used to include CSS compatibility hacks by way of a <link>
element in the page header, but they can in fact wrap any amount of HTML anywhere in the document. Read more…
XSL Date & Time Library
XSL Date & Time Library is an XSL stylesheet which provides various date and time functions for use within your own XSL stylesheets. Read more…
How to tidy up badly formatted XML with an XSL stylesheet
How do you turn this:
<broadcastScheduler><!-- ================================================================ --><!-- CURRENT SHOWS --><!-- ================================================================ --><recurr ingBroadcast href="show-varee-season-2" indexStart="26" recurFrequency="14"><firstAirDate channel ="d2" date="2007-09-21T22:00:00-06:00" dstRules="us" automaticStartup="false"/><firstAirDate chan nel="d1" date="2007-10-05T22:00:00+00:00" dstRules="eu" automaticStartup="true"/></recurringBroad cast><recurringBroadcast href="show-dan-ascherl-season-1" indexStart="6" recurFrequency="1md"><fi rstAirDate channel="d1" date="2007-05-04T22:00:00+01:00" dstRules="eu" automaticStartup="true"/>< firstAirDate channel="d2" date="2007-05-04T22:00:00-05:00" dstRules="us" automaticStartup="true"/ ><firstAirDate channel="d1" date="2007-05-18T22:00:00+01:00" dstRules="eu" automaticStartup="true "/><firstAirDate channel="d2" date="2007-05-18T22:00:00-05:00" dstRules="us" automaticStartup="tr ue"/></recurringBroadcast><recurringBroadcast href="show-bent-killer-season-1" indexStart="21" re curFrequency="14"><firstAirDate channel="d1" date="2007-08-29T19:30:00+01:00" dstRules="eu" autom aticStartup="true"/><firstAirDate channel="d2" date="2007-08-29T19:30:00-05:00" dstRules="us" aut omaticStartup="true"/></recurringBroadcast><recurringBroadcast href="show-serge-season-1" indexSt art="6" recurFrequency="7"><firstAirDate channel="d1" date="2007-05-04T22:00:00+02:00" dstRules=" eu" automaticStartup="true"/><firstAirDate channel="d2" date="2007-05-04T21:00:00-05:00" dstRules ="us" automaticStartup="true"/></recurringBroadcast><recurringBroadcast href="show-neil-bowles-se ason-1" indexStart="15" recurFrequency="14"><firstAirDate channel="d1" date="2007-11-01T23:00:00+ 01:00" dstRules="eu" automaticStartup="true"/><firstAirDate channel="d2" date="2007-11-01T23:00:0 0-05:00" dstRules="us" automaticStartup="true"/></recurringBroadcast>
into this:
<broadcastScheduler> <!-- ================================================================ --> <!-- CURRENT SHOWS --> <!-- ================================================================ --> <recurringBroadcast href="show-varee-season-2" indexStart="26" recurFrequency="14"> <firstAirDate channel="d2" date="2007-09-21T22:00:00-06:00" dstRules="us" automaticStartup="false"/> <firstAirDate channel="d1" date="2007-10-05T22:00:00+00:00" dstRules="eu" automaticStartup="true"/> </recurringBroadcast> <recurringBroadcast href="show-dan-ascherl-season-1" indexStart="6" recurFrequency="1md"> <firstAirDate channel="d1" date="2007-05-04T22:00:00+01:00" dstRules="eu" automaticStartup="true"/> <firstAirDate channel="d2" date="2007-05-04T22:00:00-05:00" dstRules="us" automaticStartup="true"/> <firstAirDate channel="d1" date="2007-05-18T22:00:00+01:00" dstRules="eu" automaticStartup="true"/> <firstAirDate channel="d2" date="2007-05-18T22:00:00-05:00" dstRules="us" automaticStartup="true"/> </recurringBroadcast> <recurringBroadcast href="show-bent-killer-season-1" indexStart="21" recurFrequency="14"> <firstAirDate channel="d1" date="2007-08-29T19:30:00+01:00" dstRules="eu" automaticStartup="true"/> <firstAirDate channel="d2" date="2007-08-29T19:30:00-05:00" dstRules="us" automaticStartup="true"/> </recurringBroadcast> <recurringBroadcast href="show-serge-season-1" indexStart="6" recurFrequency="7"> <firstAirDate channel="d1" date="2007-05-04T22:00:00+02:00" dstRules="eu" automaticStartup="true"/> <firstAirDate channel="d2" date="2007-05-04T21:00:00-05:00" dstRules="us" automaticStartup="true"/> </recurringBroadcast> <recurringBroadcast href="show-neil-bowles-season-1" indexStart="15" recurFrequency="14"> <firstAirDate channel="d1" date="2007-11-01T23:00:00+01:00" dstRules="eu" automaticStartup="true"/> <firstAirDate channel="d2" date="2007-11-01T23:00:00-05:00" dstRules="us" automaticStartup="true"/> </recurringBroadcast>
3,000 lines of the above was the horror I woke upto one day when PHP decided to stop formatting automated changes to our radio schedules properly. We need our schedules XML to be human-readable so I had to come up with a quick way to reformat it. Read more…
Unique key grouping with multiple input documents and nodesets in variables
The problem
A common requirement in XSL transformations is to group unsorted data by a key unique to each group, and sort it for display. For example:
<?xml version="1.0"?> <food> <item type="Fruit" name="Orange" /> <item type="Vegetable" name="Cucumber" /> <item type="Meat" name="Chicken" /> <item type="Vegetable" name="Carrot" /> <item type="Vegetable" name="Potato" /> <item type="Meat" name="Pork" /> <item type="Fruit" name="Banana" /> <item type="Fruit" name="Apple" /> </food>
We may typically want to output an HTML table with each food type (Fruit, Meat, Vegetable) as a header with all the items in each food category as table rows/records, ie.
Fruit |
Apple |
Banana |
Orange |
Meat |
Chicken |
Pork |
Vegetable |
Carrot |
Cucumber |
Potato |
When dealing with a single input document addressed directly (ie. not through a variable), this is a trivial problem for XSL, easily solvable using <xsl:key>
and key()
.
This technique fails when you must group a node-set stored in a variable or in an external document referenced with document()
because <xsl:key>
does not allow you to use variables or document()
in its attributes – it is only capable of indexing the main source document. Additionally, XPath axes we might use for testing uniqueness in a set (typically preceding-sibling::
in an <xsl:for-each>
to see if we have found the first occurrence of a new group key) do not function on external documents referenced by document()
.
So how do we group with XSL variables or multiple input documents? Read more…