Laurens,

The Showcase is available in its entirety as a ZIP archive. Included in this
archive are XSLT stylesheets to reformat The Register. This is a
particularly good example of XSL transformation.

Thanks for the pat on the back. I left a useless <if> in one stylesheet. I've eliminated that, eliminated the <datenum> from the sort output, and cleaned up the comments. Changed stylesheets included. I think this will be the last of the changes :-)

Ed

<?xml version="1.0" encoding="UTF-8"?>
<?jpluck name="The Register"
         description="Extract the article headings"
	       hidden="yes"
?>
<!-- written by Edward Rayl -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">
  <xsl:output method="xml" 
              indent="yes" 
              omit-xml-declaration="no" 
              encoding="utf-8"/>
  <xsl:template match="/">
    <html>
      <head>
        <!-- Get the title -->
        <base href="http://theregister.com/"/>
        <xsl:copy-of select="/html/head/title"/>
      </head>
      <body link="#0000DD" bgcolor="white">
        <!-- Get the current update date -->
        <xsl:variable name="updated">
          <xsl:value-of select="//[EMAIL PROTECTED]'indexdate']"/>
        </xsl:variable>
        <!-- Insert the 'Updated' string in the output stream 
             Use a <div> to make it appear similar to article <div>'s -->
        <div>
          <!-- Get the current banner image and format the update date-->
          <xsl:copy-of select="/html/body/table[1]//tr[1]/td[2]/a/*"/>
          <br/>
          <xsl:value-of select="normalize-space(substring-before($updated,'Updated:'))"/>
          <br/>Updated:
          <xsl:value-of select="normalize-space(substring-after($updated,'Updated:'))"/>
          <!-- Use a large datenum to make this div sort to the top
               Remember we will use a descending sort -->
          <date datenum="999999999999"/>
        </div>
        <!-- Get the article titles. We will sort the articles in the chained stylesheet -->
        <xsl:apply-templates select="//table[position()=2]//tr[position()=1]/td[position()=2]/table[position()=1]//tr[position()=2]/td/*"/>
      </body>
    </html>
  </xsl:template>

  <!-- Dates are in the form of '2 March 2003 8:32am', which makes it
         impossible to sort
       Modify this date to the normalized form of 'yyyymmddhhmm', using 24 hour format
       Add this 'date number' to the <div> as a <date datenum="yyyymmddhhmm">
         element to used by the chained stylesheet -->
  <xsl:template match="div[(@class = 'indexposted')]">
    <xsl:variable name="datenum">
      <xsl:call-template name="parseDate">
        <xsl:with-param name="date"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:element name="date">
      <xsl:attribute name="datenum"><xsl:value-of select="$datenum"/></xsl:attribute>
    </xsl:element>
    <xsl:value-of select="."/>
    <br/>
  </xsl:template>

  <!-- Process all <div>'s -->
  <xsl:template match="div">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <!-- Process miscellaneous tags in the input document -->
  <xsl:template match="node() | @*">
    <xsl:copy-of select="."/>
  </xsl:template>

  <!-- Date conversion routine -->
  <xsl:template name="parseDate">
    <xsl:variable name="date" select="."/>
    <xsl:variable name="day" select="substring-before($date, ' ')"/>
    <xsl:variable name="daylength" select="string-length($day)"/>
    <xsl:variable name="daynum">
      <!-- Change a single digit day to double digit with leading zero -->
      <xsl:choose>
        <xsl:when test="$daylength = '1'">
          <xsl:value-of select="concat('0',$day)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$day"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="month" select="substring-before(substring($date, $daylength + 2), ' ')"/>
    <xsl:variable name="monthlength" select="string-length($month)"/>
    <xsl:variable name="monthnum">
      <!-- Change a month name to two digit month number -->
      <xsl:call-template name="getMonthNum">
        <xsl:with-param name="monthname" select="$month"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="year" select="substring-before(substring($date, $daylength + $monthlength + 3), ' ')"/>
    <xsl:variable name="time" select="substring($date, $daylength + $monthlength + 8)"/>
    <xsl:variable name="timelength" select="string-length($time)"/>
    <xsl:variable name="timenum">
      <!-- Normalize 12 hour time with am/pm to 24 hour time without a ':' -->
      <xsl:choose>
        <xsl:when test="substring(substring-after($time, ':'), 3, 1) = 'p'">
          <!-- Process pm times -->
          <xsl:choose>
            <!-- 12:xxpm times do NOT get 12 added to them -->
            <xsl:when test="string(number(substring-before($time, ':'))) = 12">
              <xsl:value-of select="concat(string(number(substring-before($time, ':'))), substring(substring-after($time, ':'), 1, 2))"/>
            </xsl:when>
            <!-- add 12 to the time -->
            <xsl:otherwise>
              <xsl:value-of select="concat(string(number(substring-before($time, ':')) + 12), substring(substring-after($time, ':'), 1, 2))"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <!-- Process am times -->
          <xsl:choose>
            <xsl:when test="string-length($time) = '6'">
              <!-- Add a leading zero to single digit hours -->
              <xsl:value-of select="concat('0',substring($time, 1, 1), substring(substring-after($time, ':'), 1, 2))"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="concat(substring($time, 1, 2), substring(substring-after($time, ':'), 1, 2))"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:value-of select="concat($year, $monthnum, $daynum, $timenum)"/>
  </xsl:template>

  <!-- Change a month name to two digit month number -->
  <xsl:template name="getMonthNum">
    <xsl:param name="monthname" select="."/>
    <xsl:choose>
      <xsl:when test="$monthname = 'January'">01</xsl:when>
      <xsl:when test="$monthname = 'February'">02</xsl:when>
      <xsl:when test="$monthname = 'March'">03</xsl:when>
      <xsl:when test="$monthname = 'April'">04</xsl:when>
      <xsl:when test="$monthname = 'May'">05</xsl:when>
      <xsl:when test="$monthname = 'June'">06</xsl:when>
      <xsl:when test="$monthname = 'July'">07</xsl:when>
      <xsl:when test="$monthname = 'August'">08</xsl:when>
      <xsl:when test="$monthname = 'September'">09</xsl:when>
      <xsl:when test="$monthname = 'October'">10</xsl:when>
      <xsl:when test="$monthname = 'November'">11</xsl:when>
      <xsl:when test="$monthname = 'December'">12</xsl:when>
      <xsl:otherwise>error: <xsl:value-of select="$monthname"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<?jpluck name="The Register"
         description="Sort the article headings from The Register 
                      - chained from register-indx.xsl"
	       hidden="yes"
?>
<!-- written by Edward Rayl -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">
  <xsl:output method="xml" 
              indent="yes"
              omit-xml-declaration="no"
              encoding="utf-8"/>
  <!-- The URI of the XML/HTML page being transformed. -->

  <xsl:template match="/">
      <!-- Build the html document shell to hold the sorted <div>'s -->
      <html>
        <head>
          <xsl:copy-of select="/html/head/node()"/>
        </head>
        <body>
          <xsl:apply-templates select="/html/body"/>
        </body>
      </html>
  </xsl:template>

  <!-- Once in the body, sort the <div>'s based on the <date> tag -->
  <xsl:template match="body">
      <xsl:for-each select="div">
        <!-- Reverse sort to display the latest news at the top of the page -->
        <xsl:sort order="descending" select="date/@datenum"/>
        <!-- Grab everything except the <datenum>, we don't need it anymore -->
        <xsl:copy-of select="*[name() != 'datenum'] | text()"/>
      </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Reply via email to