The Seeds of an Idea

Necessity is the Mother of Invention

For close to fifteen years, I have been searching for a way to run a design business that helps me work better, but also works the way I want it to. I still haven’t found what I’m looking for, so I’m building it. But not without the help of a very talented crew of web application developers, Twentyone Degrees.

The Idea Began with an Application

Why build something that already exists? Because I have high standards. I want control over the design and functionality, so that I don’t have to wait for the next release to work the way I envision the process. I enjoy the details, maybe too much. I become immersed in them and lose the big picture. Probably more of a weakness than a strength. But it also helps me to do what I do.

In search of the right tool to build sites that worked well with web standards, I found one that had the potential to revolutionize content management and templating systems. The application was built on W3C standards, XML, XPath and XSLT. It is the web publishing system we know as Symphony. It does away with proprietary templating systems that do not allow for portability from one scripting language to another.

The merits of using XML / XSLT are stated well on the Overture Forum:

Once you have a system down with XML / XSLT (be it with symphony or your own homegrown solution [as is my case with the company I work for]) maintenance and adding features is a lot faster than with the traditional ‘what everyone else is doing’ methods with php. The initial overhead from the development and planning stages is more expensive but in the long run it makes life so much simpler. And it future proofs the applications you write. If you handle a lot of the logic in the XSL then if you decide that php is too slow for your application then you can essentially write a C based application that produces the same XML that your php app did and you don’t have to make any changes to your front end logic. Portability is a cinch then. One of the many reasons I love symphony. I can port most of my symphony XSL to my own content management system and have the same exact results…

That type of portability is non-existent in other solutions…

While Symphony 1.5 was in beta, during the time when Symphony was still being licensed, I started building my design portfolio website, bauhouse.ca, to showcase what was possible with Symphony. After that experience, I was hooked. The potential was huge, and the development team was extremely responsive to any questions, offering help, code samples and development services as well as application features and enhancements which found their way into the steady stream of releases since the Symphony 1.5 public release, which made the application free for anyone to use.

A Design Business Administration System

With the introduction of Campfire Services, I started to develop some thoughts around the idea of using Symphony as the hub for several business functions. The discussions I had with the Twentyone Degrees development team in September 2006 started something like this:

One of the first Campfire Services that I would be interested in developing would be some sort of front end login system for my clients. It would simply be a private area for clients to view a list of ongoing projects and to be able to view conceptual proofs and submit comments. Each client would have a code (ABC) and each job would have a number (1234).

The next stage would be to add the ability to define objectives, establish processes, schedule projects, track time, manage customers and communicate with them through e-mail, both in text and HTML, and on forums.

Then, as I grow my business into what I envision, I would want to tie this into an accounting system, with the ability to generate estimates, invoices, and financial statements, track credit card payments for typeface designs that I would offer for sale on my site, and manage members, sales and billings for subscriptions to print and online magazines.

If I could have exactly what I wish for, it would be something similar to what ProActive Software, in New Zealand, has developed as a project management solution. I took their product, ProWorkFlow, for a test drive, and I loved what they had created. The issues I had with it were its reliance on ColdFusion, the lack of an ability to modify the look of the site to match my brand, and the subscription cost per user. I could modify colours and add a logo, but beyond this, I would not be able to customize the interface. For instance, add an area for displaying conceptual work for clients, with the ability to add comments. The cost is actually fairly reasonable, but ideally, I would like a custom solution.

Another product that I have been looking at is from Marketcircle, called Daylite. They also have another product called Billings. I love the look of their applications and have been very tempted to purchase licenses for their software. I also love the idea that they are built specifically for Mac OS X from the ground up. But that is also one of their limitations. They are not cross-platform compatible, though they can be synced with mobile systems. Another problem is the proprietary database used by the software. Also, as far as I know, the features of Billings are separate from the functionality of Daylite. But I want both in one solution. And, ideally, I would want a web-based solution that looks like a desktop application and works just as fast.

In trying to solve the problems of running my business, I find that I have to cobble together a process that relies on software, both desktop and web-based, that solves each specific problem, then work them together into something that gets the job done, however inefficiently, given the repetition of certain tasks.

Instead, I have been looking for a single platform on which to build the entire process. I think Symphony is it. The first step, then, would be to set up the front end login system for my clients, which is my first priority: better communication with my clients. Then, I would want to build each of the additional modules or components onto this.

It’s all pretty ambitious, I know. But I am taking a long-term view of things. It also sounds as if you have solved a lot of these problems already with Conductor. I am very interested in seeing how this might work for me as well in trying to build a business involving identity, print, web and type design (with a view to eventually grow into industrial design and architecture – a very long-term view).

Very ambitious indeed. It’s a dream, but maybe I’ll get there one day. In the meantime, I am enjoying the process of building out these ideas, one piece at a time. Organization and business sense are one of the first things I need. They don’t come easily. But Symphony is helping.

My Symphony Feature Request

As I started thinking about how I could use Symphony, I realized I would need some additional features. I asked for them and the Symphony Team delivered. It went something like this:

It would be great to be able to cross-reference data between sections. If I was able to create a categories section and use those same categories as select box options within other sections, it would alleviate the challenge of having to manually modify the options for several sections that would access that same list of categories.

So, rather than listing options for the custom field, I could provide XSLT code that indicates a particular range of values from an XML node set in the categories datasource.

Then, I went on to explain how this might work for building websites.

I could theoretically (since I haven’t tried this) create static pages and menus for an entire site from a single master template using four sections: Sections, Categories, Entries, Pages. The master template would have a URL Schema of /section/category/entry/page/. Rather than using the default navigation data source, I could create a Sections section where each entry represents the first level in the hierarchy. This section could contain at least two custom fields:

Sections

  • Section Title
  • Section Description

Then, I could create other sections and custom fields:

Categories

  • Category Title
  • Category Description
  • Section (this custom field would be a select box listing the Sections by Section Title)

Entries

  • Entry Title
  • Entry Body
  • Category (this custom field would be a select box listing the Categories by Category Title)

Pages

  • Page Number
  • Page Title
  • Page Body
  • Entry (this custom field would be a select box listing the Entries by Entry Title)

With some creative XSLT templating, a single master template should be able to generate all menus and content dynamically without the Author ever having to touch any of the Structure or Blueprints areas of the admin, which should be restricted to Administrative users. However, all this depends on the custom field being dynamically generated by the primary custom field of another section (or, if possible, any custom field from another section). This is probably possible to accomplish now, though the custom field would have to be a Text Input field and the user would have to type the data rather than choosing it from a pull down menu. The ability to restrict choices, though, would be important to keep the site from getting broken because of user error.

Also, it would be very easy to bring back a much more powerful version of the version 1.1 Categories as you described in the Subcategories thread.

Does this sort of structure make sense as far as building a site with four levels of hierarchy?

It could also be used for building a client login / project management system.

Clients / Projects / Phases / Tasks / Entries

              <html>
    <head>
        <title>Clients / Projects / Phases / Tasks / Entries</title>
    </head>
    <body>
        <ul class="clients">
            <li class="client">Client ABC
                <ul class="projects">
                    <li class="project">Project 1234
                        <ul class="phases">
                            <li class="phase">Phase 1: Define Objectives
                                <ul class="tasks">
                                    <li class="task">Client Brief
                                        <ul class="timesheet">
                                            <li class="entry">Entry Title
                                                <ul class="entry-data">
                                                    <li class="date">2006-10-26</li>
                                                    <li class="start-time">1:00 pm</li>
                                                    <li class="stop-time">2:15 pm</li>
                                                    <li class="hours">1.25</li>
                                                    <li class="rate">75</li>
                                                    <li class="amount">93.75</li>
                                                    <li class="username">User Name</li>
                                                    <li class="description">Description</li>
                                                    <li class="notes">Notes</li>
                                                </ul>
                                            </li>
                                        </ul>
                                    </li>
                                    <li class="task">Creative Brief</li>
                                </ul>
                            </li>
                            <li class="phase">Phase 2: Research
                                <ul class="tasks">
                                    <li class="task">Research</li>
                                    <li class="task">Concept Development</li>
                                </ul>
                            </li>
                            <li class="phase">Phase 3: Design
                                <ul class="tasks">
                                    <li class="task">Preliminary Concepts</li>
                                    <li class="task">Concept Review</li>
                                    <li class="task">Concept Refinements</li>
                                    <li class="task">Concept Approval</li>
                                </ul>
                            </li>
                            <li class="phase">Phase 4: Production
                                <ul class="tasks">
                                    <li class="task">Design Production</li>
                                    <li class="task">Prepress</li>
                                    <li class="task">Final Proofs for Approval</li>
                                </ul>
                            </li>
                            <li class="phase">Phase 5: Print
                                <ul class="tasks">
                                    <li class="task">Deliver Files</li>
                                    <li class="task">Print Supervision</li>
                                    <li class="task">Delivery</li>
                                </ul>
                            </li>
                        </ul>
                    </li>
                </ul>
            </li>
        </ul>
    </body>
</html>

            

Dependencies might be built in which would require warnings that by deleting a client, all related projects and entries will be deleted, but Tasks and Phases could be global. So the actual structure would be more like:

              / Clients / Projects / Entries /

            

where the Entries section would have one required custom field for Task, which would be related to a particular Phase.

Does this make sense, or is this trying to do too much with Symphony, when there are tools like Basecamp, Harvest or ProWorkFlow?

Why build something like this in Symphony? Because of today’s announcement that Symphony 1.8 will enable the application to build other applications. The first proof of concept is the financial application that Twentyone Degrees is currently using for their inhouse operations. To find out more, visit Allen Chang’s blog on the latest news and resources for developing XSLT templates for the Symphony web publishing system, Chaotic Pattern, and listen to the podcast interview with Brad Smith and Ryan Sims from The Big Noob.

An XSLT Calendar

The First Step in Building a Design Administration Application

To develop a design business administration application, it is essential to be able to keep track of time, schedule appointments, process phases and deadlines. This means that a calendar will be one of the first requirements.

Now, we could generate calendars with JavaScript and use cookies to maintain persistent selections from one page to another. With Symphony, neither of those is necessary. Let’s let the server do the work, with XML and XSLT to produce calendar views with XHTML. Thankfully, many have done a lot of the hard work of getting a calendar to work in XSLT. There are date and time libraries available from the XSLT Standard Library. It is also possible to glean templates that perform date and time functions from EXSLT.org.

I took a look at a couple other calendar examples that I might be able to adapt, but both are dependent on external xslt libraries or functions, which is why I passed on them to begin with: trying to avoid any dependencies on external libraries. XSLT Cookbook: Creating a HTML Calendar depends on the the EXSLT.org date-time extensions. The other is A Calendar, using the XSelerator’s datetime library. In the end, I chose to use the work of Muhammad Athar Parvez on an XSL stylesheet that generates a single calendar month: Parvez’s Wing of the Gallery of Stupid XSL and XSLT Tricks.

Note: there is an interesting calendar FAQ on the issues of dates and calendars compiled by Claus Tøndering, Frequently Asked Questions about Calendars.

I started in Symphony with a static XML data source:

              <calendar>
    <year>
        <month value="1" days="31">January</month>
        <month value="2" days="28" leap-year-days="29">February</month>
        <month value="3" days="31">March</month>
        <month value="4" days="30">April</month>
        <month value="5" days="31">May</month>
        <month value="6" days="30">June</month>
        <month value="7" days="31">July</month>
        <month value="8" days="31">August</month>
        <month value="9" days="30">September</month>
        <month value="10" days="31">October</month>
        <month value="11" days="30">November</month>
        <month value="12" days="31">December</month>
    </year>
</calendar>

            

The rest of the application is a CSS file and four XSLT templates that display the four calendar views: year, month, week and day. View the calendar to see the results of this work, which extends the work of Parvez to include the additional views, navigation with persistent dates, and hours for the week and day views.

Calendar Formats

In Search of an XML Calendar Format

The most popular calendar format appears to be the ICS format used by Apple’s iCal. Unfortunately, this format is not an XML format. To be able to use this data within Symphony or with XSLT it would be helpful to be able to convert the data into a useful format. However, I was disappointed to find out that the standard for ICS files is not XML format. Apple Developer Connection points to Perl and PHP scripts that can convert ICS to XML. Strangely, I did not find any XSLT templates. I probably did not search hard enough. Most likely, XSLT is not the first place people turn to for string manipulation.

I have created an XSLT template that parses the standard ICS format and transforms it into XHTML. Here is the code that parses the properties of the ICS file into a list of properties that can be displayed in XHTML. Feed the $ical-data-raw parameter with ICS data and you will get XHTML formatted properties.

              <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output
    method="xml" 
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
    omit-xml-declaration="yes"
    encoding="UTF-8" 
    indent="yes" />

<xsl:variable name="ical-data" select="/data/vcalendar"/>
<xsl:variable name="input-data" select="normalize-space(/data/vcalendar)"/>
<xsl:variable name="ical-events">
    <xsl:value-of select="concat('BEGIN:VEVENT ',substring-before(substring-after($ical-data,'BEGIN:VEVENT'),'END:VCALENDAR'))"/>
</xsl:variable>

<xsl:template match="/">

    <h1>XSL Transform iCalendar ICS to XHTML</h1>

    <h2>iCalendar Source file</h2>
    <p><xsl:value-of select="$ical-data"/></p>



    <h2>iCalendar Data with Normalized Spaces</h2>
    <p><xsl:value-of select="$input-data"/></p>

    <h2>iCalendar Events</h2>
    <p><xsl:value-of select="$ical-events"/></p>

    <h2>Properties as XHTML</h2>
    <ul>
        <xsl:call-template name="properties"/>
    </ul>

</xsl:template>

<xsl:template name="property">
    <xsl:param name="input" select="$input-data"/>
    <xsl:param name="property" select="substring-before($input,':')"/>
    <xsl:param name="string-after-property" select="substring-after($input,':')"/>
    <xsl:param name="next-string" select="substring-before($string-after-property,':')"/>
    <xsl:param name="reverse-next-string">
        <xsl:call-template name="reverse">
            <xsl:with-param name="input" select="$next-string"/>
        </xsl:call-template>
    </xsl:param>
    <xsl:param name="reverse-next-property" select="substring-before($reverse-next-string,' ')"/>
    <xsl:param name="next-property">
        <xsl:call-template name="reverse">
            <xsl:with-param name="input" select="substring-before($reverse-next-string,' ')"/>
        </xsl:call-template>
    </xsl:param>
    <xsl:param name="value" select="substring-before($next-string, concat(' ',$next-property))"/>
    <xsl:param name="remaining-string" select="substring-after($string-after-property,concat($value,' '))"/>
    <li>Property: <xsl:value-of select="$property"/></li>
    <li>Next String: <xsl:value-of select="$next-string"/></li>
    <li>Reverse Next String: <xsl:value-of select="$reverse-next-string"/></li>
    <li>Reverse Next Property: <xsl:value-of select="$reverse-next-property"/></li>
    <li>Next Property: <xsl:value-of select="$next-property"/></li>
    <li>Value: <xsl:value-of select="$value"/></li>
    <li>Remaining String: <xsl:value-of select="$remaining-string"/></li>

    <p><xsl:value-of select="$property"/>: <xsl:value-of select="$value"/></p>
    <xsl:call-template name="next-property">
        <xsl:with-param name="input" select="$remaining-string"/>
    </xsl:call-template>
</xsl:template>

<xsl:template name="properties">
    <xsl:param name="input" select="$input-data"/>
    <xsl:param name="property" select="substring-before($input,':')"/>
    <xsl:param name="string-after-property" select="substring-after($input,':')"/>
    <xsl:param name="next-string" select="substring-before($string-after-property,':')"/>
    <xsl:param name="reverse-next-string">
        <xsl:call-template name="reverse">
            <xsl:with-param name="input" select="$next-string"/>
        </xsl:call-template>
    </xsl:param>
    <xsl:param name="reverse-next-property" select="substring-before($reverse-next-string,' ')"/>
    <xsl:param name="next-property">
        <xsl:call-template name="reverse">
            <xsl:with-param name="input" select="substring-before($reverse-next-string,' ')"/>
        </xsl:call-template>
    </xsl:param>
    <xsl:param name="value">
        <xsl:choose>
            <xsl:when test="$next-property != ''">
                <xsl:value-of select="substring-before($next-string, concat(' ',$next-property))"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$string-after-property"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:param>
    <xsl:param name="remaining-string" select="substring-after($string-after-property,concat($value,' '))"/>

    <p><xsl:value-of select="$property"/>: <xsl:value-of select="$value"/></p>
    <xsl:if test="$remaining-string != ''">
        <xsl:call-template name="properties">
            <xsl:with-param name="input" select="$remaining-string"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

<xsl:template name="reverse">
    <xsl:param name="input"/>
    <xsl:variable name="length" select="string-length($input)"/>
    <xsl:choose>
        <xsl:when test="$length &lt; 2">
            <xsl:value-of select="$input"/>
        </xsl:when>     
        <xsl:when test="$length = 2">
            <xsl:value-of select="substring($input,2,1)"/>
            <xsl:value-of select="substring($input,1,1)"/>
        </xsl:when>     
        <xsl:otherwise>
            <xsl:variable name="middle" select="floor($length div 2)"/>
            <xsl:call-template name="reverse">
                <xsl:with-param name="input" select="substring($input,$middle + 1,$middle + 1)"/>
            </xsl:call-template>
            <xsl:call-template name="reverse">
                <xsl:with-param name="input" select="substring($input,1,$middle)"/>
            </xsl:call-template>
        </xsl:otherwise>        
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

            

I have completed building the XSLT templates that can output xCalendar. It should be a trivial matter to adjust the templates to output the hCalendar format as well (see also the W3C presentation on Semantic Web Data Integration with hCalendar and GRDDL. This will allow iCal files to be easily parsed to test the ability of the XSLT Calendar to be able to display iCal information.

The xCalendar format will be most useful as an XML data source for building XHTML pages.

              <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE iCalendar PUBLIC "-//IETF//DTD XCAL/iCalendar XML//EN"
"http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt">

<iCalendar>
    <vcalendar method="PUBLISH"
        version="2.0"
        prodid="-//HandGen//NONSGML vGen v1.0//EN">
        <vevent>
            <uid>19981116T150000@cal10.host.com</uid>
            <dtstamp>19981116T145958Z</dtstamp>
            <summary>Project XYZ Review</summary>
            <location>Conference Room 23A</location>
            <dtstart>19981116T163000Z</dtstart>
            <dtend>19981116T190000Z</dtend>
            <categories>
                <item>Appointment</item>
            </categories>
        </vevent>
    </vcalendar>
</iCalendar>

            

XSLT Transformation of ICS to XML

An XSLT Template to Convert iCalendar Files to xCalendar Files

I wanted to find an XSLT template that would be able to parse an iCalendar ICS file into an XML format that would work well with the calendar application I had built with XSLT and Symphony. What I found was an XSLT template that converted XML to ICS. I found nothing that was able to reverse the process. So I created an XSLT template that can convert ICS to the xCalendar format.

There is one minor problem that I couldn’t get past, which was to create XML elements for the values of those properties that have multiple values, such as the rrule or category elements. I developed the following template with the help of Marc Liyanage’s TextXSLT application.

              <?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output
    method="xml" 
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
    omit-xml-declaration="yes"
    encoding="UTF-8" 
    indent="yes" />

<xsl:param name="ical-data-raw" select="/data/vcalendar"/>
<xsl:param name="ical-data" select="normalize-space($ical-data-raw)"/>
<xsl:param name="ical-properties" select="substring-before($ical-data,' BEGIN:VEVENT')"/>
<xsl:param name="ical-events">
<xsl:value-of select="concat('BEGIN:VEVENT ',substring-before(substring-after($ical-data,'BEGIN:VEVENT '),' END:VCALENDAR'))"/>
</xsl:param>

<xsl:template match="/">

    <h1>XSL Transformation of iCalendar ICS format to XHTML</h1>

    <h2>Individual iCalendar Events</h2>

    <h3>iCalendar to xCalendar XSL Transformation</h3>
    <xsl:call-template name="xcal-calendar">
        <xsl:with-param name="input" select="$ical-properties"/>
        <xsl:with-param name="type" select="'calendar'"/>
        <xsl:with-param name="output-format" select="'xcalendar'"/>
    </xsl:call-template>

</xsl:template>

<xsl:template name="xcal-calendar">
    <xsl:param name="input"/>
    <xsl:param name="type" select="'event'"/>
    <xsl:param name="output-format" select="'xcalendar'"/>
    <xsl:param name="ical-properties-data" select="$input"/>
    <xsl:param name="remaining-event-data" select="substring-after($input, $ical-properties-data)"/>
    <xsl:choose>
        <xsl:when test="$output-format = 'xcalendar'">
            <iCalendar>
                <vcalendar>
                    <xsl:call-template name="properties">
                        <xsl:with-param name="input" select="$ical-properties-data"/>
                        <xsl:with-param name="type" select="$type"/>
                        <xsl:with-param name="output-format" select="$output-format"/>
                    </xsl:call-template>
                    <xsl:call-template name="xcal-events">
                        <xsl:with-param name="input" select="$ical-events"/>
                        <xsl:with-param name="type" select="'event'"/>
                        <xsl:with-param name="output-format" select="$output-format"/>
                    </xsl:call-template>
                </vcalendar>
            </iCalendar>
        </xsl:when>
        <xsl:when test="$output-format = 'xcalendar-encoded'">
            <code><pre>
            <xsl:text>&lt;iCalendar&gt;&#xd;</xsl:text>
            <xsl:text>&lt;vcalendar&#xd;</xsl:text>
            <xsl:call-template name="properties">
                <xsl:with-param name="input" select="$ical-properties-data"/>
                <xsl:with-param name="type" select="$type"/>
                <xsl:with-param name="output-format" select="$output-format"/>
            </xsl:call-template>
            <xsl:text>&gt;&#xd;</xsl:text>
            <xsl:call-template name="xcal-events">
                <xsl:with-param name="input" select="$ical-events"/>
                <xsl:with-param name="type" select="'event'"/>
                <xsl:with-param name="output-format" select="$output-format"/>
            </xsl:call-template>
            <xsl:text>&lt;/vcalendar&gt;&#xd;</xsl:text>
            <xsl:text>&lt;/iCalendar&gt;&#xd;</xsl:text>
            </pre></code>
        </xsl:when>
    </xsl:choose>
    <xsl:if test="$remaining-event-data != ''">
        <xsl:call-template name="xcal-calendar">
            <xsl:with-param name="input" select="$remaining-event-data"/>
            <xsl:with-param name="type" select="$type"/>
            <xsl:with-param name="output-format" select="$output-format"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

<xsl:template name="xcal-events">
    <xsl:param name="input"/>
    <xsl:param name="type" select="'event'"/>
    <xsl:param name="output-format" select="'xcalendar'"/>
    <xsl:param name="ical-event-data" select="concat('BEGIN:VEVENT ',substring-before(substring-after($input,'BEGIN:VEVENT '),' END:VEVENT'),' END:VEVENT')"/>
    <xsl:param name="remaining-event-data" select="substring-after($input, $ical-event-data)"/>
    <xsl:choose>
        <xsl:when test="$output-format = 'xcalendar'">
            <vevent>
                <xsl:call-template name="properties">
                    <xsl:with-param name="input" select="$ical-event-data"/>
                    <xsl:with-param name="type" select="$type"/>
                    <xsl:with-param name="output-format" select="$output-format"/>
                </xsl:call-template>
            </vevent>
        </xsl:when>
        <xsl:when test="$output-format = 'xcalendar-encoded'">
            <xsl:text>&#x9;&lt;vevent&gt;&#xd;</xsl:text>
                <xsl:call-template name="properties">
                    <xsl:with-param name="input" select="$ical-event-data"/>
                    <xsl:with-param name="type" select="$type"/>
                    <xsl:with-param name="output-format" select="$output-format"/>
                </xsl:call-template>
            <xsl:text>&#x9;&lt;/vevent&gt;&#xd;</xsl:text>
        </xsl:when>
        <xsl:when test="$output-format = 'hcalendar'">
        </xsl:when>
    </xsl:choose>
    <xsl:if test="$remaining-event-data != ''">
        <xsl:call-template name="xcal-events">
            <xsl:with-param name="input" select="$remaining-event-data"/>
            <xsl:with-param name="type" select="$type"/>
            <xsl:with-param name="output-format" select="$output-format"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

<xsl:template name="properties">
    <xsl:param name="input" select="$ical-data"/>
    <xsl:param name="type" select="'event'"/>
    <xsl:param name="output-format" select="'xcalendar'"/>
    <xsl:param name="property-and-attribute-caps" select="substring-before($input,':')"/>
    <xsl:param name="property-and-attribute" select="translate($property-and-attribute-caps,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"/>
    <xsl:param name="property">
        <xsl:choose>
            <xsl:when test="contains($property-and-attribute,';')">
                <xsl:value-of select="substring-before($property-and-attribute,';')"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$property-and-attribute"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:param>
    <xsl:param name="property-attribute" select="substring-after($property-and-attribute,';')"/>
    <xsl:param name="property-attribute-name" select="substring-before($property-attribute,'=')"/>
    <xsl:param name="property-attribute-value" select="substring-after($property-attribute,'=')"/>
    <xsl:param name="string-after-property" select="substring-after($input,':')"/>
    <xsl:param name="next-string" select="substring-before($string-after-property,':')"/>
    <xsl:param name="reverse-next-string">
        <xsl:call-template name="reverse">
            <xsl:with-param name="input" select="$next-string"/>
        </xsl:call-template>
    </xsl:param>
    <xsl:param name="reverse-next-property" select="substring-before($reverse-next-string,' ')"/>
    <xsl:param name="next-property">
        <xsl:call-template name="reverse">
            <xsl:with-param name="input" select="substring-before($reverse-next-string,' ')"/>
        </xsl:call-template>
    </xsl:param>
    <xsl:param name="string-before-next-property" select="substring-before($next-string, concat(' ',$next-property))"/>
    <xsl:param name="plural-values" select="contains($string-before-next-property,';')"/>
    <xsl:param name="multiple-items">
        <xsl:if test="$plural-values">
            <xsl:value-of select="translate($string-before-next-property,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"/>
        </xsl:if>
    </xsl:param>
    <xsl:param name="items">
        <xsl:call-template name="items">
            <xsl:with-param name="input" select="$multiple-items"/>
            <xsl:with-param name="output-format" select="$output-format"/>
        </xsl:call-template>
    </xsl:param>
    <xsl:param name="value">
        <xsl:choose>
            <xsl:when test="$next-property != '' and contains($string-before-next-property,';') and $output-format = 'xcalendar-encoded'">
                <xsl:value-of select="$items"/>
            </xsl:when>
            <xsl:when test="$next-property != ''">
                <xsl:value-of select="$string-before-next-property"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$string-after-property"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:param>
    <xsl:param name="remaining-string" select="substring-after($string-after-property,concat($value,' '))"/>
    <xsl:if test="$property != 'begin' and $property != 'end'">
        <xsl:choose>
            <xsl:when test="$type = 'event'">
                <xsl:choose>
                    <xsl:when test="$output-format = 'xcalendar'">
                        <xsl:choose>
                            <xsl:when test="$property-attribute-name = 'value'">
                                <xsl:element name="{$property}">
                                    <xsl:attribute name="{$property-attribute-name}"><xsl:value-of select="$property-attribute-value"/></xsl:attribute>
                                    <xsl:value-of select="$value"/>
                                </xsl:element>
                            </xsl:when>
                            <xsl:when test="$plural-values and $output-format = 'xcalendar'">
                                <xsl:element name="{$property}">
                                    <xsl:copy-of select="$items"/>
                                </xsl:element>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:element name="{$property}">
                                    <xsl:value-of select="$value"/>
                                </xsl:element>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:when>
                    <xsl:when test="$output-format = 'xcalendar-encoded'">
                        <xsl:choose>
                            <xsl:when test="$property-attribute-name = 'value'">
                                <xsl:text>&#x9;&#x9;&lt;</xsl:text>
                                <xsl:value-of select="$property"/>
                                <xsl:text> </xsl:text>
                                <xsl:value-of select="$property-attribute-name"/>
                                <xsl:text>="</xsl:text>
                                <xsl:value-of select="$property-attribute-value"/>
                                <xsl:text>"&gt;</xsl:text>
                                <xsl:value-of select="$value"/>
                                <xsl:text>&lt;/</xsl:text>
                                <xsl:value-of select="$property"/>
                                <xsl:text>&gt;&#xd;</xsl:text>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:text>&#x9;&#x9;&lt;</xsl:text>
                                <xsl:value-of select="$property"/>
                                <xsl:text>&gt;</xsl:text>
                                <xsl:value-of select="$value"/>
                                <xsl:text>&lt;/</xsl:text>
                                <xsl:value-of select="$property"/>
                                <xsl:text>&gt;&#xd;</xsl:text>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:when>
                </xsl:choose>
            </xsl:when>
            <xsl:when test="$type = 'calendar'">
                <xsl:choose>
                    <xsl:when test="$output-format = 'xcalendar'">
                        <xsl:attribute name="{$property}"><xsl:value-of select="$value"/></xsl:attribute>
                    </xsl:when>
                    <xsl:when test="$output-format = 'xcalendar-encoded'">
                        <xsl:text>&#x9;</xsl:text>
                        <xsl:value-of select="$property"/>
                        <xsl:text>="</xsl:text>
                        <xsl:value-of select="$value"/>
                        <xsl:text>"</xsl:text>
                    </xsl:when>
                </xsl:choose>
            </xsl:when>
        </xsl:choose>
    </xsl:if>
    <xsl:if test="$remaining-string != ''">
        <xsl:if test="$property != 'begin' and $property != 'end' and $output-format = 'xcalendar-encoded' and $type = 'calendar'">
            <xsl:text>&#xd;</xsl:text>
        </xsl:if>
        <xsl:call-template name="properties">
            <xsl:with-param name="input" select="$remaining-string"/>
            <xsl:with-param name="type" select="$type"/>
            <xsl:with-param name="output-format" select="$output-format"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>


<xsl:template name="items">
    <xsl:param name="input"/>
    <xsl:param name="items" select="$input"/>
    <xsl:param name="output-format" select="'xcalendar'"/>
    <xsl:param name="delimiter" select="';'"/>
    <xsl:param name="item-and-value">
        <xsl:choose>
            <xsl:when test="contains($items,$delimiter)">
                <xsl:value-of select="substring-before($items,$delimiter)"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$items"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:param>
    <xsl:param name="remaining-items" select="substring-after($items,$delimiter)"/>
    <xsl:param name="item" select="substring-before($item-and-value,'=')"/>
    <xsl:param name="value" select="substring-after($item-and-value,'=')"/>
    <xsl:choose>
        <xsl:when test="$output-format = 'xcalendar'">
            <item class="{$item}">
                <xsl:value-of select="$value"/>
            </item>
        </xsl:when>
        <xsl:when test="$output-format = 'xcalendar-encoded'">
            <xsl:text>&#xd;&#x9;&#x9;&#x9;&lt;</xsl:text>
            <xsl:value-of select="$item"/>
            <xsl:text>&gt;</xsl:text>
            <xsl:value-of select="$value"/>
            <xsl:text>&lt;/</xsl:text>
            <xsl:value-of select="$item"/>
            <xsl:text>&gt;</xsl:text>
        </xsl:when>
    </xsl:choose>
    <xsl:if test="$remaining-items != ''">
        <xsl:call-template name="items">
            <xsl:with-param name="input" select="$remaining-items"/>
            <xsl:with-param name="output-format" select="$output-format"/>
        </xsl:call-template>
    </xsl:if>
    <xsl:if test="$remaining-items = ''">
        <xsl:text>&#xd;&#x9;&#x9;</xsl:text>
    </xsl:if>
</xsl:template>


<xsl:template name="reverse">
    <xsl:param name="input"/>
    <xsl:variable name="length" select="string-length($input)"/>
    <xsl:choose>
        <xsl:when test="$length &lt; 2">
            <xsl:value-of select="$input"/>
        </xsl:when>     
        <xsl:when test="$length = 2">
            <xsl:value-of select="substring($input,2,1)"/>
            <xsl:value-of select="substring($input,1,1)"/>
        </xsl:when>     
        <xsl:otherwise>
            <xsl:variable name="middle" select="floor($length div 2)"/>
            <xsl:call-template name="reverse">
                <xsl:with-param name="input" select="substring($input,$middle + 1,$middle + 1)"/>
            </xsl:call-template>
            <xsl:call-template name="reverse">
                <xsl:with-param name="input" select="substring($input,1,$middle)"/>
            </xsl:call-template>
        </xsl:otherwise>        
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

            

Author Registration Campfire Services

Twentyone Degrees Campfire Services

It is time to release these Campfire Services into the wild: developed as custom CS for a front end member registration system.

I could try to continue development of these resources on my own, and try to develop a business model that might support ongoing development of these Campfire Services and of The Design Administration application. My motivation, though, is not foremost a revenue source. It is enhanced functionality for the best CMS I have yet to come across, Symphony. The best idea I have come up with so far is a dropcash campaign. So here they are for all to try out. Go to the resources page to download the files.