toIcal.xsl 5.52 KB
<?xml version='1.0'?><!-- -*- mode: nxml -*- -->
<xsl:transform
    xmlns:xsl  ="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:c    ="http://www.w3.org/2002/12/cal/ical#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    >

<div xmlns="http://www.w3.org/1999/xhtml">

<h1>toIcal.xsl -- a syntactic transformation of RDF Calendar to ICalendar</h1>

<p>see also:</p>
<ul>
<li><a href="http://rdfig.xmlhack.com/2004/11/10/2004-11-10.html#1100057031.061434">dev notes</a></li>
<li><a href="http://www.ietf.org/internet-drafts/draft-hare-xcalendar-01.txt">draft-hare-xcalendar-01</a></li>
</ul>

<p>@@open source license... part of <a href="http://www.w3.org/2002/12/cal/">RDF Calendar Workspace</a></p>

<address><a href="http://www.w3.org/People/Connolly/">Dan Connolly</a><br />
<small>$Id: toIcal.xsl,v 1.4 2004/11/10 06:50:28 connolly Exp $</small>
</address>

<pre>
$Log: toIcal.xsl,v $
Revision 1.4  2004/11/10 06:50:28  connolly
now passes test/spec01-conf3.rdf !
thanks to ASPN for string replace function

Revision 1.3  2004/11/10 06:12:19  connolly
fixed xpath in CAL-ADDRESS properties
almost passes test/spec01-conf3.rdf, save newlines in description

Revision 1.2  2004/11/10 05:03:34  connolly
oops; got CR/LF mixed up a few times

Revision 1.1  2004/11/10 04:38:49  connolly
got it convert all of test/spec01-conf3.rdf
trying to run the results thru fromIcal.py

</pre>
</div>

<blockquote xmlns="http://www.w3.org/1999/xhtml">
<pre>
   each conforming document MUST include reference to an
   XSL stylesheet which can transform the document into a standard
   iCalendar [RFC 2445] document of MIME	content-type "text/calendar".
</pre>
</blockquote>
<xsl:output method="text" media-type="text/calendar"/>

<!-- component syntax -->
<xsl:template match="c:Vcalendar
		     |c:Vtimezone|c:standard|c:daylight
		     |c:Vevent">
  <xsl:text>BEGIN:</xsl:text>

  <!-- iCalendar is case insensitive, right? -->
  <xsl:value-of select='local-name()'/>

  <xsl:text>&#13;&#10;</xsl:text>
  <xsl:apply-templates />
  <xsl:text>END:</xsl:text>
  <xsl:value-of select='local-name()'/>
  <xsl:text>&#13;&#10;</xsl:text>
</xsl:template>


<!-- text properties -->
<xsl:template match="c:calscale|c:prodid|c:version
		     |c:tzid
		     |c:uid
		     |c:summary|c:description
		     |c:status
		     |c:categories
		     ">
  <xsl:value-of select='local-name()'/>
  <xsl:text>:&#13;&#10; </xsl:text>

  <xsl:call-template name="textVal">
    <xsl:with-param name="val" select="text()"/>
  </xsl:call-template>
</xsl:template>


<!-- date-time properties -->
<xsl:template match="c:dtstamp
		     |c:dtstart|c:dtend">
  <xsl:value-of select='local-name()'/>
  <xsl:text>:&#13;&#10; </xsl:text>

  <!-- 1996-07-04T12:00:00Z becomes 19960704T120000Z -->
  <xsl:value-of select="translate(.,':-','')"/>

  <xsl:text>&#13;&#10;</xsl:text>
</xsl:template>


<!-- CAL-ADDRESS properties -->
<!-- hmm... XML Schema types might be a good fit. -->
<xsl:template match="c:organizer">
  <xsl:value-of select='local-name()'/>
  <xsl:text>:&#13;&#10; </xsl:text>

  <!-- hmm... calAddress is an odd construct -->
  <!-- is iCalendar serious about capital MAILTO:? -->
  <xsl:value-of select="c:calAddress/@rdf:resource" />

  <xsl:text>&#13;&#10;</xsl:text>
</xsl:template>


<!-- syntactically invisible bits -->
<xsl:template match="rdf:RDF|c:component">
  <xsl:apply-templates />
</xsl:template>

<xsl:template match="*">
  <xsl:message>
    @@unmatched element:
    <xsl:value-of select='name()'/>
  </xsl:message>
</xsl:template>


<xsl:template name="textVal">
  <xsl:param name="val"/>
  <xsl:call-template name="emit_text">
    <xsl:with-param name="line">
      <!-- @@ rfc2445#sec4.3.11 says to quote these too:
           DQUOTE, ";", ":", "\", ","
	-->
      <xsl:call-template name="replace-string">
	<xsl:with-param name="text" select="$val"/>
	<xsl:with-param name="from" select='"&#10;"'/>
	<xsl:with-param name="to" select='"\n"'/>
      </xsl:call-template>
    </xsl:with-param>
  </xsl:call-template>
</xsl:template>


<!-- ACK: lifed directly from draft-hare-xcalendar-01  -->
<xsl:template name="emit_text">
  <xsl:param name="limit" select="number(75)"/> <!-- default limit is 75 " -->
  <xsl:param name="line"/>
  <xsl:value-of select="substring(normalize-space($line),1,$limit)" />
  <!-- Output the newline string -->
  <xsl:text>&#13;&#10;</xsl:text>
  <xsl:if test="string-length($line) > $limit">
    <xsl:text> </xsl:text>
    <xsl:call-template name="emit_text">
      <xsl:with-param name="limit" select="($limit - 1)" /> <!-- use 74 allow for space -->
      <xsl:with-param name="line" select="substring($line,($limit + 1))" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>


 <!-- ACK: ASPN
  http://aspn.activestate.com/ASPN/Cookbook/XSLT/Recipe/65426
  -->
 <xsl:template name="replace-string">
    <xsl:param name="text"/>
    <xsl:param name="from"/>
    <xsl:param name="to"/>

    <xsl:choose>
      <xsl:when test="contains($text, $from)">

	<xsl:variable name="before" select="substring-before($text, $from)"/>
	<xsl:variable name="after" select="substring-after($text, $from)"/>
	<xsl:variable name="prefix" select="concat($before, $to)"/>

	<xsl:value-of select="$before"/>
	<xsl:value-of select="$to"/>
        <xsl:call-template name="replace-string">
	  <xsl:with-param name="text" select="$after"/>
	  <xsl:with-param name="from" select="$from"/>
	  <xsl:with-param name="to" select="$to"/>
	</xsl:call-template>
      </xsl:when> 
      <xsl:otherwise>
        <xsl:value-of select="$text"/>  
      </xsl:otherwise>
    </xsl:choose>            
 </xsl:template>

</xsl:transform>