Showing posts with label Xslt. Show all posts
Showing posts with label Xslt. Show all posts

Tuesday, 15 June 2010

Sitecore link fields put /home in the target URL's href

When using sc:fld('fieldname', ., 'url') in an XSLT rendering to get a link field's target URL, you will find that the href includes '/home'. This is rarely desirable. Thankfully, it's easy to solve. Simply use sc:fld('fieldname', ., 'id') instead to get the target ID. You can then pass the ID to sc:path().

Tuesday, 23 March 2010

How to remove an apostrophe from a string in Sitecore XSLT

Given a variable named "string", you can remove apostrophes by declaring a variable to hold the apostrophe and then passing that to the sc:Replace method:

<xsl:variable name="apos">'</xsl:variable>
<xsl:variable name="string"
select="sc:Replace( $input, $apos, '' )" />

Friday, 14 August 2009

Write to Sitecore log file from XSLT

It is simple to write to the Sitecore log file from within an XSLT file without having to write any custom code. We can just hook up to the Sitecore.Diagnostics.Log class and call one of its methods.

In the web.config, define the extension under <xslextensions>:

<extension mode="on"
type="Sitecore.Diagnostics.Log, Sitecore.Kernel"
namespace="http://www.sitecore.net/log"
singleInstance="true" />

Within the XSLT file, add a prefix that matches the namespace you used in the above step:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sc="http://www.sitecore.net/scReal"
xmlns:dot="http://www.sitecore.net/dot"
xmlns:log="http://www.sitecore.net/log"
exclude-result-prefixes="dot sc log">

The Log class contains a number of overloads for Info, Warn, Error and so on. Some of these expect an exception as a parameter, so we cannot call these direct from XSLT. We can, however match the overloads that expect a string and an object (eg. Warn( String, Object )):

<xsl:value-of select="log:Warn('Warning message', 'Another string... perhaps the name of your rendering file')" />

That's it! Now you can log whatever you like from within your renderings.

Tuesday, 28 July 2009

Enable XSLT IntelliSense within Visual Studio

Wouldn't it be nice to have Visual Studio list the available template names when typing out a call-template statement in XSLT? Wouldn't it also be nice to have it list available parameter names when typing out a with-param statement?

To enable these autocompletions and more, you need to back up your registry and then run regedit. Within regedit, create a string value called "XsltIntellisense" under "HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\XmlEditor" key, giving it the value "True". That's it!

Ultimately, I'd like to see full IntelliSense for XSLT in Visual Studio, but this is a good start.

Friday, 16 January 2009

Screen reader friendly phone numbers

When you display a telephone number on screen, screen readers read it out as a single number. The Fangs screen reader emulator (see http://sourceforge.net/projects/fangs) reads the number (01234) 567890 as “left paren six hundred sixty-eight right paren five hundred sixty-seven thousand eight hundred ninety”. The “six hundred sixty-eight” bit is particularly curious: the 01234 is being interpreted as an octal number.

By encasing each digit within a <span /> tag, the digits are read out individually. So, (01234) 567890 becomes “left paren zero one two three four right paren five six seven eight nine zero”.

I have written an XSLT template that takes a phone number and applies a <span /> to each digit:

<xsl:template name="DisplayPhoneNumber">
<xsl:param name="position" />
<xsl:param name="phonenumber" />
<xsl:variable name="digit"
select="substring($phonenumber, $position, 1)" />

<xsl:choose>
<xsl:when test="contains('012345678', $digit)">
<span>
<xsl:value-of select="$digit" />
</span>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$digit" />
</xsl:otherwise>
</xsl:choose>

<xsl:if test="$position &lt;
string-length($phonenumber)">
<xsl:call-template name="DisplayPhoneNumber">
<xsl:with-param name="position">
<xsl:value-of select="$position+1" />
</xsl:with-param>
<xsl:with-param name="phonenumber"
select="$phonenumber" />
</xsl:call-template>
</xsl:if>
</xsl:template>

To call the template, pass in the telephone number and prime the starting position using a value of 1:

<xsl:call-template name="DisplayPhoneNumber">
<xsl:with-param name="position" select="'1'" />
<xsl:with-param name="phonenumber"
select="'(01234) 567890'" />
</xsl:call-template>


If you’re using this within Sitecore, you can simply pass in a field value in the usual way:

<xsl:call-template name="DisplayPhoneNumber">
<xsl:with-param name="position" select="'1'" />
<xsl:with-param name="phonenumber"
select="sc:fld('phone', .)" />
</xsl:call-template>

Thursday, 21 February 2008

Extract the Month from a DateTime Field in Sitecore

Using sc:formatdate(), it is a fairly trivial matter to format a date in a Sitecore Xslt rendering. Eg:
sc:formatdate(sc:fld('MyDateField', .),
'd MMM yyyy @ h:mm')

However, extracting just the month as a number without padding is less obvious. Using the format string 'MMM' gives three-letter month names, 'MM' gives months padded with zeros (eg. 02 for Feb), while 'M' curiously gives full month name and date padded with zeros.

A workaround is to use substring-after in conjunction with the format '/M'. Example:
substring-after(sc:formatdate(
sc:fld('MyDateField', .), '/M'), '/')

Friday, 15 February 2008

Get the Path of a Sitecore File Field Given a Media Path

A file field in Sitecore uses a media path. If you want to get the actual URL to the uploaded file, you need to append the file’s media path to the media library path and use this to reference the item in the media library. You can then extract the value of the path field. Example:

<a href="{sc:fld('Path', sc:item(concat('/sitecore/media library', sc:fld('filefieldname', .)), .))}">Download file</a>

Monday, 11 February 2008

Setting Query String Parameters in Xslt

In Xslt, adding a new parameter to a query string presents a problem as, without writing your own extension function, you cannot determine whether you should prefix your parameter with ‘?’ or ‘&’. In Sitecore, the Xslt function sc:qs('parametername') can be used to obtain the value of a named parameter parametername. Unfortunately, there is no function provided that obtains the entire query string.

Here’s a workaround. Let’s say you want to add a parameter called ‘page’.

First, build up the rest of the query string. The following template checks the existence in the query string of parameter names passed to it. You need to know the names of the possible parameters. If they exist, they are written out.

<xsl:template name="SetQueryParameter">
<xsl:param name="name" />
<xsl:if test="sc:qs($name)">
<xsl:text>&amp;</xsl:text>
<xsl:value-of select="$name" />
<xsl:text>=</xsl:text>
<xsl:value-of select="sc:qs($name)" />
</xsl:if>
</xsl:template>

This template would typically be called from within a variable definition, therefore saving the created query string. In the following example, we are checking parameters type and orderby and saving them if they exist so we can add them back in later:

<xsl:variable name="RestOfQueryString">
<xsl:call-template name="SetQueryParameter">
<xsl:with-param name="name">type</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="SetQueryParameter">
<xsl:with-param name="name">orderby</xsl:with-param>
</xsl:call-template>
</xsl:variable>

You are then able to append this query string to your newly-added parameter, which you add using a ‘?’:

<a>
<xsl:attribute name="href">
<xsl:text>?page=10</xsl:text>
<xsl:value-of select="$RestOfQueryString" />
</xsl:attribute>
<xsl:text>Page 10</xsl:text>
</a>

Tuesday, 15 January 2008

Implementing the MVP Pattern in Sitecore XSLT Extension Methods

Here’s a way of implementing the MVP pattern when creating Sitecore XSLT extension methods. Ideally, you should already have some experience of creating extension methods and be familiar with MVP.

In the example I use, a “for-each” loop is used to display a list of makes of car.

First, create the view interface, defining the property or properties you want to display in the XSLT. As we are returning an array of values, the XPathNodeIterator return type is used:

public interface ICarsView
{

    XPathNodeIterator Cars { get; set; }

}


Create an interface defining the method that will get the data or information from store:

public interface ICar
{

    XPathNodeIterator GetListOfCars();

}


In your data access layer (DAL), implement the method that gets the data:

public XPathNodeIterator GetListOfCars()

{

    var cars = from c in GetMyData()

               orderby c.Make

               select c;

 

    XDocument xdoc = new XDocument();

    XElement xmlTree = new XElement("Cars");


    foreach( var car in cars )

    {

        xmlTree.Add(new XElement("Car",

            new XAttribute("Make", car.Make)));

    }


    xdoc.Add(xmlTree);


    return xdoc.CreateNavigator().Select("/Cars/Car");

}


Create the presenter class, which will store references to the view and DAL method interfaces, and define the method(s) that will set the value of the property or properties on the view:

    public class CarsPresenter

    {

        private readonly ICarsView _view;

        private readonly ICar _icar;

 

        public CarsPresenter( ICarsView view, ICar car )

        {

            _view = view;

            _icar = car;

        }

 

        public void SetCarsProperty()

        {

            _view.Cars = _icar.GetListOfCars();

        }

    }



Create the extension method that implements the view:

public class CarsView: ICarsView
{
    public XPathNodeIterator GetListOfCars()
    {
        CarsPresenter cp = new CarsPresenter(this, new CarsDal());
        cp.SetCarsProperty ();
        return Cars;
    }
 
    #region IAgreementsView Members
 
    public XPathNodeIterator Cars
    {
        get; set;
    }
 
    #endregion
}


In the web.config file, add an extension element to the xslExtensions element that references the concrete view. Use one such element for each namespace:

<extension mode="on" type="XsltViews.CarsView, XsltViews"
           namespace=" http://example.com/xsltviews/cars " />


In your XSLT file, declare the namespace prefix by adding it to the stylesheet element and including the prefix in the exclude-result-prefixes attribute:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:sc="http://www.sitecore.net/sc"
  xmlns:dot="http://www.sitecore.net/dot"
  xmlns:view="http://example.com/xsltviews/cars"
  exclude-result-prefixes="dot sc view">


Finally, you can now call the method from your XSLT:

<xsl:for-each select="view:GetListOfCars()">
  <xsl:value-of select="@Make"/>
</xsl:for-each>

Monday, 14 January 2008

Creating Simple Loops in XSLT

Here's a simple way to create a loop in XSLT. As you might expect, it uses recursion.

I have defined a template that will do the work of the loop. It checks the value of a variable called 'counter' before calling itself. This is the loop condition. Before this test, you can add whatever it is you need the loop to do. In the following example, I print the letters of the alphabet, followed by "... Hello!":

<xsl:template name="DoLoop">
<xsl:param name="counter" />
<xsl:variable name="letter"
select="substring($alphabet, $counter, 1)" />

<!--Body of loop goes here-->

<xsl:value-of select="$letter" />... Hello!
<br/>

<!--End of loop body-->

<xsl:if test="$counter &lt; 26">
<xsl:call-template name="DoLoop">
<xsl:with-param name="counter">
<xsl:value-of select="$counter+1" />
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>

The loop is then initiated by calling it with the desired starting value:

<xsl:call-template name="DoLoop">
<xsl:with-param name="counter">1</xsl:with-param>
</xsl:call-template>

For info, the alphabet variable is simply defined as:

<xsl:variable name="alphabet">
<xsl:text>ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:text>
</xsl:variable>

Thursday, 3 January 2008

How to Change String Case in XSLT

Here's a simple way to convert a string to lower case in XSLT. The snippet takes an input variable inputtext and saves the lower case version to a new variable called lowercasetext.

<xsl:variable name="lowercasetext" select="translate($inputtext, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" />

To upper case a string, simply swap the position of the two alphabet literals shown.