• Get the Flash Player to see the slideshow.
  • Categories

  • Authors

  • Great Quotes

    It always seems impossible until its done. — Nelson Mandela

Get in touch...

To have a chat about
your CMS needs...

Call us 0207 193 2014
or
Email us on

Archive for the ‘XSL’ Category

XSL:Sort by Date, Organise by Type

Monday, March 2nd, 2009

In this example, we have a collection of material which we want to make available to users: whitepapers, articles, tips etc.  We want to group these by material and show the relevant subheading when this changes, but avoid redisplaying the heading if it remains the same, say:

Whitepaper

Article

As per other examples, the key to doing this is to ensure we have the collection sorted correctly before we consider displaying them:

<xsl:apply-templates select="[list of items being processed]">
<xsl:sort select="./type"/>
<xsl:sort order="descending" select="substring(./created,7,4)"/>
<xsl:sort order="descending" select="substring(./created,4,2)"/>
<xsl:sort order="descending" select="substring(./created,1,2)"/>
</xsl:apply-templates>

At this point we have a set of items in ascending alphabetical types, reverse ordered by date.

We then call the familiar block to begin processing.

There is now some logic required here to say, if repeat type do not display, if a new type display.

In a scripting language, the obvious solution is to store the type in a variable, and do something if the new type differs from the last stored type.

Restrictions on <xsl:variable> mean we cannot do this.

Loosely, in XSLT position() translates to count [forwards].  XLST has a function that is similar to ‘count backwards’ which is preceding-sibling [OK, it means invert the node set and count forwards, but you get the idea].

Therefore by saying preceding-sibling::*[1]/type XPath expression say “go to the first preceding sibling, then get its type element’s contents” and the expression provides a ready means of testing “is the current value the same as the last one”.

It is worth pointing out that this is a sophisticated function, there are similar ones such as following-sibling, preceding, ancestor, or ancestor-or-self which may be more appropriate to the use required.

It is also important to note the use of ‘*[1]/type’.  The * is a wildcard and this would not work if there were multiple child elements type within the given element.  The [1] is important too as this means go-back-one: or, more accurately, reverse the list and read the next … If the [1] was omited, the expression would say, look backwards anywhere in the list.

Finally, reading backwards would return a null value if the top of the list was reached, so a failsafe is required to make sure we are not at the top of the list.

<xsl:choose>
<xsl:when test="position() = 1">
<!-- display the type-->
<xsl:value-of select="./type"/>
</xsl:when>
<xsl:when test="position() &gt; 1">
<!-- only read backwards now we have read at least one record -->
<xsl:if test="./type != preceding-sibling::*[1]/type">
<!-- only if the type has changed-->
<xsl:value-of select="./type"/>
</xsl:if>
</xsl:when>
</xsl:choose>

XSL:Sort By Date, Limit Returned Results

Monday, March 2nd, 2009

In an accompanying article, a simple method to sort by date was introduced.

Normally it is desirable to limit the number of results shown.

There are various complex ways of doing this posted on other sites, the fundamental problem being that <xsl:variable> works as a constant in practice, i.e set only once.

Trying to implement a counter as per scripting languages becomes difficult – although not impossible – so rather than fight against the restrictions XSLT gives, better to use the inbuilt position() function, which will tell you how far it has progressed along the current record set.

Provided all the select criteria have been applied to the record set FIRST, the position() function will effectively map to counter.

To complete the process, set a global variable (probably based on a Datum) to fix the displayed items

<xsl:variable name="x-rows" select="//Datum[@Name='FixLimit']"/>
 
<xsl:template match="/">
 
<xsl:apply-templates select=”[some repeating datum]“&gt;
<xsl:sort order=”descending” select=”substring(//somedate,7,4)> <!-- year->
<xsl:sort order=”descending” select=”substring(//somedate,4,2)> <!-- month-->
<xsl:sort order=”descending” select=”substring(//somedate,1,2)> <-- day-->
 
</xsl:apply-templates>

Now in the add a ‘count’ test for each time the executes:

<xsl:template match=”[match repeating datum]>
   <xsl:if test="position() &lt;= $x-rows">
   ...
   </xsl:if>
</xsl:template>

to stop processing once the row limit has been reached.

XSL:Sort By Date

Monday, March 2nd, 2009

The following  should do the work

<xsl:apply-templates select="[some repeating datum]">
<xsl:sort order="descending" select="substring(//somedate,7,4)"> <!-- year-->
<xsl:sort order="descending" select="substring(//somedate,4,2)"> <!-- month-->
<xsl:sort order="descending" select="substring(//somedate,1,2)"> <!-- day-->
</xsl:apply-templates>

This assumes the date is in the form dd/mm/yyyy: the seperators could be different as they are ignored anyway based on the substring.

The important thing to realise here is that the <xsl:sort> functions do not do anything APART from sort, so there is nothing to see at this point if debugging

The work is done in a receiving

<xsl:template match="[match repeating datum]">
 
...
 
</xsl:template>

The ensures items are delivered to this block in the correct order, what is displayed is determined in the section

XSL Extract File Suffix, Convert to Uppercase, Display

Monday, March 2nd, 2009
<xsl:value-of
select="translate(substring-after(/Properties/Data/Datum[@Name='filename'],'.'),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>

Keeping XML Tags in XSL

Friday, February 27th, 2009

Problem

In your XSL you want to grab an XML document “as is” but the XSL keeps stripping the XML tags and only returning data values to you.

My LiveSite Component was connecting to a XML WebService and in one case I only wanted to retrieve all the XML and return it to my XSL.

I was struggling as the XSL was removing all the tags and leaving just the contents of the tags.

Here is what I did:

Solution

Use XSL Copy – your XSL should look like:

  <xsl:template match="/"> 
          <xsl:copy-of select="/"/> 
  </xsl:template>

Important

You must set your Page Settings to “XML” in order to see this correctly – you will not be able to Preview correctly in the LiveSite component development branch as you have no control over the page settings here.

LiveSite XSL Reference II

Friday, November 28th, 2008

Nested Quotations with XSL

It is not unusual to come across a situation where nested quotations fail (are exceeded) in an apperance XSL document.

Say I want to tie a Javascript function to an input control, but I want to pass the value of a datum-type as an argument to the funtion.

Therefore I want to describe an attribute value something of the order “JavaScript:handleJSFunction (’//Datum[@Name="someDatum"]‘);”

In practice this will fail as the nested quotes will not resolve (and CDATA will not work either, it will generate errors).

The solution is to take the theoretical expression:

<input type=”checkbox” name=”cb_boolean1″ value=”false” onClick=”JavaScript:handleJSFunction (’//Datum[@Name="someDatum"]‘);”/>

and break out the expression using <xsl:attribute/> tags, then using <xsl:text/> together with <xsl:value-of/> to concentatate the attribute string value with the required Datum value (s), thus avoiding interpolation errors::

            <input>
               <xsl:attribute name=”type”><xsl:text>checkbox</xsl:text></xsl:attribute>
               <xsl:attribute name=”name”><xsl:text>cb_boolean1</xsl:text></xsl:attribute>
               <xsl:attribute name=”value”><xsl:text>false</xsl:text></xsl:attribute>
               <xsl:attribute name=”onClick”>
                 <xsl:text>JavaScript:handleJSFunction(’</xsl:text>
                 <xsl:value-of select=”//Datum[@Name='someDatum']“/>
                 <xsl:text>’);</xsl:text>
               </xsl:attribute>

       </input>

 

Removing newlines in XSL

Friday, October 3rd, 2008

Thansk to Mark Stradling for this tip, the below little template is useful to remove new lines using XSL:

<xsl:template name="removelines"> 
  <xsl:param name="text" /> 
  <xsl:value-of select="translate($text,'&#x0A','')" /> 
</xsl:template>

Process XML Documents on the CLI

Thursday, August 21st, 2008

You can query or manipulate XML documents on the command-line using either XSH, the PERL XML Shell, or even easier, use xmlstarlet, a windows/unix binary, available from http://xmlstar.sourceforge.net

Work with LiveSite Components “Offline”

Friday, August 8th, 2008

If you are developing LiveSite components in a shared environment, the chances are high that your editing will be interrupted by other users performing builds. To get around this you can bypass the online environment, and access the component files direct.

1) Use Samba or a tool such as FileZilla to access the component files. If you are using FileZilla, set the editor to VIM.

2) Select “view/edit” in FileZilla to access each LiveSite component.

3) The component file is very difficult to read as the XSL code has amongst other things,  < and > replaced with < and >

4) To remedy the above, add the following functions and menu options to your VIM environment :-

” Make a LiveSite component more readable
func MakeComponentReadable()
%s/</<|/g
%s/>/|>/g
%s/</</g
%s/>/>/g
%s/ /<cr\/>/g
set syntax=xml
1
endf

” Restore a LiveSite component back to it’s original state prior to uploading
func RestoreComponent()
%s/<cr\/>/\ /g
%s/\([^\|]\)>/\1\>/g
%s/<\([^\|]\)/\<\1/g
%s/<|/</g
%s/|>/>/g
set syntax=
1
endf

amenu one.Make\ LS\ Component\ Readable :call MakeComponentReadable()<CR><ESC>
amenu one.Restore\ LS\ Component :call RestoreComponent()<CR><ESC>

5) The first function adds readability to the component file, whilst the second is used to restore the standard component formatting once your editing is done, and you are ready to upload the component back to the LS environment.

VIM Functions and Menu Items for Writing XSL

Thursday, July 31st, 2008

Add the following lines to a myxsl.vim file and place it in your VIM plugins directory.

The next time you start VIM, you will have a menu called “lf” appear with the following items

listed that allow you to create more xsl code with less typing.

Note that you must also add the VIM utility functions listed in a previous blog article, found here:

http://www.littleforest.co.uk/vim-unix/vim-toolkit-functions/ 

amenu lf.xsl:template\ w\ name :call XslTemplateWithName()<CR><ESC>
amenu lf.xsl:call-template :call XslCallTemplate()<CR><ESC>
amenu lf.xsl:param :call XslParam()<CR><ESC>
amenu lf.xsl:with-param :call XslWithParam()<CR><ESC>
amenu lf.xsl:if :call XslIf()<CR><ESC>
amenu lf.xsl:choose :call XslChoose()<CR><ESC>
amenu lf.xsl:when :call XslWhen()<CR><ESC>
amenu lf.xsl:otherwise :call XslOtherwise()<CR><ESC>
amenu lf.xsl:variable :call XslVariable()<CR><ESC>
amenu lf.xsl:value-of :call XslValueOf()<CR><ESC>
amenu lf.xsl:text :call XslText()<CR><ESC>
amenu lf.xsl:for-each :call XslForEach()<CR><ESC>
amenu lf.xsl:sort :call XslSort()<CR><ESC>

func! XslTemplateWithName()
        let n=inputdialog(”Template Name”)
        call P(”<xsl:template name=\”" . n . “\”>”)
        call P(”</xsl:template>”)
        call Up()
endf

func! XslForEach()
        let n=inputdialog(”Select Expression”)
        call P(”<xsl:for-each select=\”" . n . “\”>”)
        call P(”</xsl:for-each>”)
        call Up()
endf

func! XslCallTemplate()
        let n=inputdialog(”Template Name”)
        call P(”<xsl:call-template name=\”" . n . “\”>”)
        call P(”</xsl:call-template>”)
        call Up()
endf

func! XslSort()
        let n=inputdialog(”Sort Select Expression”)
        call P(”<xsl:sort select=\”" . n . “\”/>”)
endf

func! XslParam()
        let n=inputdialog(”Param Name”)
        call P(”<xsl:param name=\”" . n . “\”/>”)
endf

func! XslWithParam()
        let n=inputdialog(”Param Name”)
        let v=inputdialog(”Param Value”)
        call P(”<xsl:with-param name=\”" . n . “\”>” . v . “</xsl:with-param>”)
endf

func! XslIf()
        let n=inputdialog(”Test Expression”)
        call P(”<xsl:if test=\”" . n . “\”>”)
        call P(”</xsl:if>”)
        call Up()
endf

func! XslChoose()
        call P(”<xsl:choose>”)
        call P(”</xsl:choose>”)
        call Up()
endf

func! XslAttribute()
        let n=inputdialog(”Attribute Name”)
        call P(”<xsl:attribute name=\”" . n . “\”>”)
        call P(”</xsl:attribute>”)
        call Up()
endf

func! XslText()
        call P(”<xsl:text></xsl:text>”)
endf

func! XslWhen()
        let n=inputdialog(”Test Expression”)
        call P(”<xsl:when test=\”" . n . “\”>”)
        call P(”</xsl:when>”)
        call Up()
endf

func! XslOtherwise()
        call P(”<xsl:otherwise>”)
        call P(”</xsl:otherwise>”)
        call Up()
endf

func! XslVariable()
        let n=inputdialog(”Variable Name”)
        let v=inputdialog(”Variable Value”)
        call P(”<xsl:variable name=\”" . n . “\”>” . v . “</xsl:variable>”)
        call Up()
endf

func! XslValueOf()
        let n=inputdialog(”Variable Name”)
        call P(”<xsl:value-of select=\”" . n . “\”/>”)
endf