Doing a Double Take with Sakai Portfolio XSL

Indiana University's version of the page composer idea allows students to create up to 7 top level pages in their portfolio. By default these pages are:

  • Welcome
  • About Me
  • Goals
  • Philosophy
  • Classes and Projects
  • Work Showcase
  • Resume

The form schema for any one of these pages includes fields for what they want to call this page (perhaps renaming their "Welcome" page to "Howdy"), he name of the page as they wish to see it in the secondary menu, a rich text editor area for the content of the page and a "subform" group where they can add additional subpages under this main menu item. For example, a "Goals" page could have subpages related to professional, academic and personal goals.

The subpage section of the form allows the student to name the subpage, select a category from a list (for example, you could have categories for "Hobbies", "Family", "Academic Background", etc. as categories available for "About Me" subpages) and to provide the content for the page.

A snippet of the XML generated from filling out a page form has a structure sort of like this:

  • artifact
    • structuredData
      • portfolioPage
        • title (the name of the page as it appears in the portfolio main menu)
        • sidePageName (the name of the page as it would appear in the portfolio secondary menu)
        • content (the HTML meat of the 1st page in the section)
        • subPage
          • title (the name of the subPage as it appears in the portfolio secondary menu)
          • category (a tag by which we wish to group all of the subpages)
          • pageContent (the HTML meat of the subPage)
        • subPage
          • title (the name of the subPage as it appears in the portfolio secondary menu)
          • category (a tag by which we wish to group all of the subpages)
          • pageContent (the HTML meat of the subPage)

The secondary menu for a section of the portfolio would need to look something like this:

  • THE SIDE PAGE NAME
  • Uncategorized Page 1
  • Uncategorized Page 2
  • CATEGORY #1
  • Category #1 Subpage A
  • Category #1 Subpage B
  • CATEGORY #2
  • Category #2 Subpage A
  • Category #2 Subpage B

So, you can see that the way that they are presented in the original XML isn't quite what I need. I sort of wished that the XML had a structure more like what my target looked like. Maybe something like this:

  • artifact
    • structuredData
      • portfolioPage
        • title (the name of the page as it appears in the portfolio main menu)
        • sidePageName (the name of the page as it would appear in the portfolio secondary menu)
        • content (the HTML meat of the 1st page in the section)
        • uncategorizedPages
          • subPage
            • title (the name of the subPage as it appears in the portfolio secondary menu)
            • pageContent (the HTML meat of the subPage)
        • categories
          • category
            • categoryName
            • subPage
              • title (the name of the subPage as it appears in the portfolio secondary menu)
              • pageContent
            • subPage
              • title (the name of the subPage as it appears in the portfolio secondary menu)
              • pageContent
          • category
            • categoryName
            • subPage
              • title
              • pageContent
            • subPage
              • title
              • pageContent

Since this XML structure would more closely resemble my target HTML structure, it would be a lot easier to write my XSLT against THAT piece of XML.

If only I could do two transformations! (Cue the dream sequence effects...)

  • Transformation 1 would take the XML I am given and give me the XML I want.
  • Transformation 2 would take this new XML and give me the HTML I want.

Well, whatta you know...you can.

I stumbled across this bit from IBM's developerworks which describes a process that creates your intermediate XML as string content in a variable and then apply a template against that XML using the node-set function, which converts your variable string content (which can't be processed) to an XML node set (which can).

The node-set function is can be used if you declare the exsl namespace in your stylesheet (xmlns:exsl="http://exslt.org/common").

It looks like this:

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

  <xsl:template match="/ospiPresentation">

    <xsl:variable name="intermediateXML">
       <intermediateXMLRootElement>
            (Your XSL to go from what you have to what you want)
       </intermediateXMLRootElement>
    </variable>

    <!-- This will give you your intermediate XML right in the browser. -->
    <xsl:copy-of select="exsl:node-set($intermediateXML)"/>

    <!-- or you can use it, just like you want to -->
    <xsl:for-each select="exsl:node-set($intermediateXML)/intermediateXMLRootElement/whateverYouWant">
        (whatever you want to do)
    </xsl:for-each>

  </xsl:template>

</xsl:stylesheet>

I think this might have a couple of benefits to template developers.

  1. It breaks the problem into two parts. If you are doing some grouping of content with XSL keys and generating unique ID's, that is really a different problem than generating HTML for display. Abstracting one problem from the other made solving the whole easier.
  2. It makes troubleshooting your XSL easier. I liked that I could do a check and see if I was getting the right intermediate XML in my variable.
  3. It promotes more code reuse. If I wanted to generate a different set of HTML, I may be able to reuse the intermediate XML code as my "base".