URL construction in XSLT

Motivation

Portlet spec attempts to isolate portlets from knowing the details of the URL parameter syntax. uPortal3 relies on such isolation to allow for transparent syntax configuration. This was not the case in uPoratl2 and XSLT rendering commonly constructed URLs explicitly, by appending string parameters to the baseActionUrl. In uPortal3, all possible URLs would have to be pre-generated and passed as separate params, which isn't practical. This section documents another approach - using Xalan extension elements. This is related to the following JIRA issues: UPT-88

Portlet URLs

Portlet URL construction is implemented by PortletUrlXalanElements. The following example shows element use:

<!-- note declaration of xalan namespace, a portlet namespace and
its designation as an extension prefix -->
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xalan="http://xml.apache.org/xalan"
    xmlns:portlet="http://uportal.org/portletUrl"
    extension-element-prefixes="portlet">
  
  <!-- declaration of the extension component -->
  <xalan:component prefix="portlet" elements="renderUrl portletUrl parameter windowState portletMode secure">
      <xalan:script lang="javaclass" src="org.jasig.portal.portlet.url.impl.PortletUrlXalanElements"/>
  </xalan:component>

  <!-- construction of a portlet render URL -->
  <xsl:variable name="exampleUrl">
      <!-- the following example will generate a portlet render url that
           will pass request parameter, and set portlet window state -->
      <portlet:renderUrl>
          <portlet:parameter name="parameterName" value="parameter value"/>
          <portlet:windowState state="normal"/>
      </portlet:renderUrl>
  </xsl:variable>
  <!-- use constructed url -->
  <a href="${exampleUrl}"/>


  <!-- construction of an action URL -->
  <xsl:variable name="anotherUrl">
      <!-- the following example will generate a portlet action url that
           sets an action request parameter, portlet mode, and specifies
           that URL should be in secure mode -->
      <portlet:actionUrl>
          <!-- note that attributes are evaluated by standard rules -->
          <portlet:parameter name="someName" value="${xpath}"/>
          <portlet:portletMode mode="edit"/>
          <portlet:secure value="true"/>
      </portlet:actionUrl>
  </xsl:variable>

  <!-- targeting other portlets: all of the elements, except for secure,
       can take optional windowId parameter to target a different windowId -->
  <xsl:variable name="advancedUrl">
      <!-- the following example will generate a portlet render url that
           will pass a render request parameters and portlet modes for
           different portle twindows -->
      <portlet:renderUrl>
          <portlet:parameter windowId="someId" name="parameterName" value="parameter value"/>
          <portlet:portletMode windowId="anotherId" mode="view"/>
      </portlet:renderUrl>
  </xsl:variable>
</xsl:stylesheet>

The outer <actionUrl> or <renderUrl> element evaluates to a string, and should be usable just like any other string-valued XSLT element. However, due to a Xalan bug, using extension element within <xsl:attribute/> directly fails:

<a>
   <xsl:attribute name="href">
      <portlet:renderUrl>
         <portlet:parameter name="pname" value="pvalue"/>
      </portlet:renderUrl>
   </xsl:attribute>
</a>

The extension element can, however, be used within regular output elements, although it's not clear how much utility that has:

<a>
   <portlet:renderUrl>
      <portlet:parameter name="pname" value="pvalue"/>
   </portlet:renderUrl>
</a>

That's why the examples above assing the url to a variable prior to using it. Hopefully this will be fixed in the next release.

Framework URLs

Portlet URL elements described above can be used for portlet stylesheet development. In framework stylesheets, a different outer element is used, impelemnted by PortalUrlXalanElements.
The following example illustrates how to construct URLs for managing rendering attributes in the framework stylesheets (i.e. transformations driven by TransformerFilterImpl):

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xalan="http://xml.apache.org/xalan" 
    xmlns:portal="http://uportal.org/portalUrl" 
    xmlns:rendering="http://uportal.org/renderingUrl" 
    extension-element-prefixes="portal rendering">
    
    <!-- outer portal URL element -->
    <xalan:component prefix="portal" elements="url">
        <xalan:script lang="javaclass" src="org.jasig.portal.url.PortalUrlXalanElements"/>
    </xalan:component>
    
    <!-- rendering attribute URL construction elements -->
    <xalan:component prefix="rendering" elements="attribute parameter">
        <xalan:script lang="javaclass" src="org.jasig.portal.rendering.attributes.RenderingAttributeProviderXalanElements"/>
    </xalan:component>
    
    <xsl:template match="doc">
        <!-- set rendering param for the structure attribute provider, using a string value -->
        <xsl:variable name="simpleParamUrl">
            <portal:url>
                <rendering:parameter source="structure" name="param1" value="value1"/>
            </portal:url>
        </xsl:variable>
        <test description="simple parameter set"><xsl:value-of select="$simpleParamUrl"/></test>
        
        <!-- set rendering param using an XPath expression for value -->
        <xsl:variable name="xpathParamUrl">
            <portal:url>
                <rendering:parameter source="structure" name="param1" value="{//folder[UPC:@ID='1']/@name}"/>
            </portal:url>
        </xsl:variable>
        <test description="xpath parameter set"><xsl:value-of select="$xpathParamUrl"/></test>
        
        <!-- set rendering attribute by selecting a current context node.
        The URL below will set attribute1 for a folder with ID=5 to "value1"
        -->
        <xsl:for-each select="//folder[UPC:@ID='5']">
            <xsl:variable name="simpleAttribute">
                <portal:url>
                    <rendering:attribute source="theme" name="attribute1" value="value1"/>
                </portal:url>
            </xsl:variable>
            <test description="simple atttribute of the current node"><xsl:value-of select="$simpleAttribute"/></test>
        </xsl:for-each>
        
        <!-- set rendering attributes for a specific element specified by the "select" attribute.
        The URL below will set attribute attribute3 for folder with ID=7 to the value of the type attribute on that folder
        -->
        <xsl:variable name="singleXpathNodeAttribute">
            <portal:url>
                <rendering:attribute source="theme" name="attribute2" value="{//folder[UPC:@ID='7']/@type}" select="//folder[UPC:@ID='7']"/>
            </portal:url>
        </xsl:variable>
        <test description="simple atttribute of a single selected node"><xsl:value-of select="$singleXpathNodeAttribute"/></test>
        
        <!-- set rendering attributes for a set of elements using "select" attribute.
        The URL below will set attribute attribute3 to "value3" for all folders with attribute type="someType"
        -->
        <xsl:variable name="multipleXpathNodesAttribute">
            <portal:url>
                <rendering:attribute source="structure" name="attribute3" value="value3" select="//folder[UPC:@type='someType']"/>
            </portal:url>
        </xsl:variable>
        <test description="xpath atttribute of multiple selected nodes"><xsl:value-of select="$multipleXpathNodesAttribute"/></test>

        <!-- use the extension element directly, without declaring a variable first 
             Note that this can not be done within <xsl:attribute/> element
        -->
        <test description="using extension element directly, without a variable declaration">
            <portal:url>
                <rendering:attribute source="structure" name="attribute3" value="value3" select="//folder[UPC:@type='someType']"/>
            </portal:url>
        </test>

    </xsl:template>
    
</xsl:stylesheet>