First XSLT Function

YouTube function

Let’s see what we want to create and then make it. Simple steps at a time; this might just be the first XSLT function you are creating.

What is it we will make?

Our aim here is what you see in the screenshot of a page on my C1 CMS demo site. This part of the template shows two content areas. The one area has pure content…

Figure 1: Showing pure content

…while the other one shows the YouTube video.

Figure 2: Showing a YouTube video inline

So we want editors to be able to add these to their page. We need to make it simple for them to insert these content elements anywhere they want to. If you don’t want the editors to have that much freedom in where to insert and play videos on the pages, you can consider using datatypes - a little more on that later!

Below is the same page in the manager: the template with three content areas the editor can supply content for.

Figure 3: Block 1 contains nothing but HTML

And Block 2 has the function inserted to play the YouTube video. This is what you will be able to create in a few minutes after you study this document!

Figure 4: Block 2 includes a YouTube video

Note: In my design the blocks have a fixed height; that is why the content below the function is not visible. I have just left it so in here to make clear that this function can just go anywhere on a page between content elements etc.

If you do the preview, you will see the video again as in the first screenshot.

How to embed a YouTube video

There are two ways to go with YouTube videos: link or embed. We want to play the video on our site, not just link to it. (An editor can do that just by supplying a hyperlink but that is boring.) So visit the YouTube website and find the code to embed a video on your site.

On the YouTube site, when having found a video, now get the embed code.

Figure 5: Video on YouTube

Here is the code copied straight from the site:

<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/CVvC80xoWmI&amp;hl=en&amp;fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/CVvC80xoWmI&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object>

Listing 1: The Embed code from the YouTube website

Have a look at the code: which code is standard and which differs per video? If you’re not sure, get another video, get its embed code and compare the two.

Let’s beautify the code a bit for readability:

<object width="425" height="344">
  <param 
  name="movie"
  value="http://www.youtube.com/v/CVvC80xoWmI&amp;hl=en&amp;fs=1"></param>
  <param name="allowFullScreen" value="true"></param>
  <param name="allowscriptaccess" value="always"></param>
  <embed 
  src="http://www.youtube.com/v/CVvC80xoWmI&amp;hl=en&amp;fs=1"  type="application/x-shockwave-flash" 
  allowscriptaccess="always" 
  allowfullscreen="true" 
  width="425" 
  height="344">
  </embed>
</object>

Listing 2: The same code formatted for readability

We can see that it has an <object> element with some parameters and an <embed> element.

It looks duplicated, which it is. This is how it takes care of different browsers.

Using the YouTube code from C1 CMS

Let’s first copy this code to a blank page in C1 CMS. Be sure not to copy the word stuff into your browser. This is code not content.

If you copy and paste it, or better insert as the Word, it will come out as text. What we need is it keeping HTML tags, not content on a page. Therefore, we need to paste it in as code.

  • Select to the Content perspective in C1 CMS
  • Create a new page or edit an existing page
  • Select the Content tab
  • Switch to the Source code view (the Source button right on top of Visual editor)
  • Paste the HTML in

Figure 6: HTML pasted in the Source view

Now click the Preview tab. Oh no! An error… Too bad it does not work!

Don’t be put off immediately. I agree that they are nasty and can be really cryptic but always try to find something in that error message!

Figure 7: An error displayed in the Preview

It is complaining about ‘=’ at Line 4 Position 60 where it expects a ‘;’. Let’s see if we can fix it there. At Line 4 we see a lot of equal signs. Position 60 must be somewhere at the end:

value="http://www.youtube.com/v/CVvC80xoWmI&hl=en&fs=1

There we see “CVvC80xoWmI&hl=en&fs=1”. Well this is “&hl=” it doesn’t like.

It expects something like “&code;” and it reads something like “&code=” which is not allowed in XHTML, and C1 CMS validates your output for that and, therefore, complains.

In order to ensure validity of strings like that, ampersands must be expressed themselves as an entity reference, i.e. "&amp;” For example:

value="http://www.youtube.com/v/CVvC80xoWmI&amp;hl=en&amp;fs=1

Note: Please refer to Using Ampersands in Attribute Values (and Elsewhere) for more information.

The strange string of characters just before the ampersand “CVvC80xoWmI” is actually the unique YouTube video code. If you look at different <embed> elements, you will see that this one changes for each video. If you change anything there you will see either no video or another one. It is the unique way to specify which video you want to see. That is exactly what we need later on, and it is what we will have the editors specify. So leave that code intact for now.

Usually you will just try to take out pieces that cause problems and see if you can still get it to work. So I took out the “&hl=en&fs=1” part and then it started complaining about another line.

Yes, indeed, there you find the similar one in the <src> value of the <embed> element. Clear them both out and the preview works now! It plays your video (just give it a little bit of time to load it from YouTube)

I am leaving you with the following working code:

<object width="425" height="344">
<param 
name="movie" value="http://www.youtube.com/v/CVvC80xoWmI"></param>
<param name="allowFullScreen" value="true"></param>
<param name="allowscriptaccess" value="always"></param>
<embed 
src="http://www.youtube.com/v/CVvC80xoWmI" type="application/x-shockwave-flash" 
allowscriptaccess="always" 
allowfullscreen="true" 
width="425" 
height="344">
</embed>
</object>

Listing 3: The modified code that works now

This code works, and to play another video, you have to change that video code. So we have found the main variable part in here: “CVvC80xoWmI”. So if we want to play a YouTube video, we need to put in all this HTML code and the code of the video we want to see.

To put in some HTML code on a page you can use an XSLT function. This is what we will make now.

To put in an input variable for the video code we can create an input parameter in this function.

Your first XSLT function

You’re still here, not feared away by that complex error, good! It will not get any more complex than that!

We will now create a XSLT function, which will write some HTML, the HTML we have just managed to get correctly rendered by C1 CMS with the page preview.

To create a new function, select the Functions perspective.

There you can see the list of functions available on your site. It might be empty or list a whole lot of them depending on your site implementation and add-ons installed. I have a bunch of them.

Now you will create the function by right clicking in the XSLT Function part of the Functions navigator and clicking Add Function in the context menu.

Figure 8: About to add an XSLT function

Naming functions

Think well about the name for a function! When editors will want to add a YouTube video, they must insert the function from this list of functions. Giving a good name will make the function easier to find and group with similar functions.

You might consider using different namespaces. If you are creating the function as a partner, you might have a namespace of “Partner name functions”, or for a specific customer - “Customer name functions”. You can see that C1 CMS uses its own namespace as well: all the add-ons are under within the “Composite” namespace, as well as items in other perspectives such as “Media”. This is important; but for now we will not go deeper into this.

Creating an XSLT function

To create a new function:

  1. Select the Functions perspective
  2. Select the XSLT functions in the navigator’s tree
  3. Click Add Function
  4. Specify the name
  5. Specify the namespace
  6. Click OK

I named the function MyYoutube and entered “Demo.Media” as the namespace. Meaning you will have a namespace called Media below the already existing Demo namespace.

Note: namespaces are case-sensitive, so if you type demo.media, you will have two demonamespaces: Demo and demo, which might not be your idea of ordering functions.)

Output type XHTML

Leave the output type as XHTML, so that we will have XHTML generated. The other choice is XML. Putting it on XHTML will make the function available in the Insert Function list of Visual Editor. In most cases, you will be creating XHTML functions.

When going much more advanced on, you might want to create XML that is used in other functions; in that case, you’ll have to change the output type.

Figure 9: Editing an XSLT function

The function is created. The namespace now shows in the function tree.

An XSLT function editor view consists of several tabs. It opens on the Template tab, which shows the XSLT. This is where you specify the output of the function. Here you will add the XHTML and any XSLT needed to render XHTML. We will get to the other tabs later.

Let’s start simple, with “hello world”. You can replace the entire inner <body> section with some of your html. Click on the Preview tab to see the result:

Figure 10: Previewing the XSLT function.

Smaller steps: inserting a new function

If you want to take smaller steps, you can now save this function and test it.

For the limited functionality it has now, it only shows “Hello World!” in my case.

To do so:

  1. From the Content perspective, edit a page,
  2. Switch to the Visual view if necessary
  3. Insert the function (Insert > Function)
  4. Then click to expand Demo.Media and you will see your function there.
  5. Select it and click OK.

Figure 11: Inserting the function

Now you can see the green box with your function’s name appeared on a page. Add some content above and below your function. Click Preview to see the result.

Figure 12: The function has been inserted

Okay, that works. Now let’s go back to the function again and add something better than just “Hello World!” to it.

Rendering YouTube code

Now remove “HELLO WORLD” and add that YouTube code we made earlier. Hopefully, you kept it in Notepad somewhere (Personally I use Notepad++, a free, very handy editor with many cool features, I often have multiple documents open in where I paste parts of code). Otherwise go back in this document to the proper section and copy it again.

  • Copy the YouTube object embed code
  • Paste the code in the <body> section of the XSLT template.
  • Save the function.

If you took the smaller steps, you can switch to the Content perspective again. If you still have that page with your function open, you can click on the Preview tab again. This is a great way of testing your function on a page. Click back and forth from the function and content section (the same works well when modifying templates)

Figure 13: Pasting the YouTube HTML embed code in the function

But this will always show the same YouTube video. Now we need to make it dynamic. An editor should supply that video code. To do so, we can use the Input Parameters of a XSLT function.

  1. Click on the Input Parameters tab
  2. Click Add New (input parameter)
  3. Type “VideoCode” in the field name. This is the name of our variable, we need this later in the specific casing
  4. Specify the Label and Help fields to give more friendly names and explanation about what this input parameter is used for. For example, I have specified “Copy the move id code from YouTube in here ( like 64Nl7Mhnugo from http://www.youtube.com/watch?v=64Nl7Mhnugo)” in the Help field.

Figure 14: Adding an input parameter

In the Parameter type and values, you specify, of which type the VideoCode parameter is and what the value of the parameter will be, or better where we will get it from.

We need something like “CVvC80xoWmI” to fit in there, which is a string.

Let’s create a test value with that string in there:

  1. Click the Test value. Two windows will pop up.
  2. Click Set New.
  3. Select the function Composite | Constant | String. The function opens and shows that it has a parameter : Value)
  4. Specify the value for the String constant function by choosing Constant and then pasting our video code in.

    Figure 15: Specifying the constant value –video code

  5. Click OK.

    You see, you are using CMS functions and input parameters, just like you do with your own right now.

  6. Click the Preview tab.

Figure 16: Previewing the modified function

You can see our input parameter with the test value appearing in the preview. We will now get that parameter into the XHTML we have specified in the Template. This is where we need to do a little XSLT coding.

Learning the basics of XSLT

This document is not intended to teach you that; but it will give you some bits to start with.

XSLT is quite complex to master but it is quite easy to change if you learn the basics. XSLT works very well on reuse. (Installing add-ons from our package server will provide you with good examples, although some are aimed at a more complex level.)

Once you have gathered some XSLTs, do a lot of googling and practicing in, for example, the free XRay XML Editor. You will learn a lot about XSLT. Focus on learning the basics, see how XSLT looks. You don’t have to be able to write XSLT from scratch nor understand it fully to use and modify it! You will often be able to use a complex XSLT by only changing some simple bits and pieces!

Learn the XPath, learn the template basics and spot the xsl:value-of bits. These are the basic things you need to change in XSLTs. Paste the input XML from your functions into your editor (XRay or better XMLSpy) and code the XSLT in there until you are satisfied, then paste the XSLT back in here.

You will not learn anything specific to C1 CMS here. Just open standards XML and XSLT that you can reuse in many other different projects and products. You can also consult other people knowing nothing of C1 CMS but knowing XSLT.

To start learning XSLT I have created a page on a personal site with some links and tips to resources and other interesting things: http://Vinnie.nerdnet.nl/xslt.

Getting the video code variable with XSLT

As was said, we will not try to teach you XSLT in here, so here we go with only short bits.

We have <in:param name="videocode">CVvC80xoWmI</in:param> which needs to go in our XHTML.

Create a variable in XSLT and set the value with our XML using XPath query:

<xsl:param name="videocode" select="/in:inputs/in:param[@name='videocode']" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" />

Create the $videocode variable and select the value from our <in:inputs …> <in:paramname="videocode">…

Now to refer to variables in XSLT, you use something like this:

<xsl:value-of select="@attribute" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" />
<xsl:value-of select="$variable" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" />

With @ you are referring to XML attributes, with $ you are referring to XSLT variables.

If you want a variable within an XHTML element you will use the {$variable notation}

<strong><xsl:value-of select="$variable" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" /></strong>
<img src="{$variable}"/>

So to put the $videocode in the right spot, you will get to

<param name="movie" value="http://www.youtube.com/v/{$videocode}" />

The same counts for:

<embed src="http://www.youtube.com/v/{$videocode}" />

Test it using the preview, and see that the test value appears in the XHTML.

Voila! you managed to pull an input parameter into the output XHTML.

Okay, we managed to get an input parameter into our XHTML but it is still a constant value. We want the editors to specify the value for the videocode input parameter themselves.

This is what the default value is for. Until now we have been having the test value do this. This test value is not required in your function, but it can be handy for testing your function.

  1. Save your function.
  2. Switch to the Content perspective again.
  3. Preview.

Another error!

Instead of your function a [ Error in rendering ] appears! Nasty, but again don’t be put off! I’m actually ‘forcing’ these errors onto you to experience them and now to deal with them.

  1. Click on the error.
  2. Read the error in the popup
System.InvalidOperationException: Failed to get value for function 'Demo.Media.MyYoutube'. ---> System.ArgumentException: Missing parameter 'videocode' (type of System.String)
   at Composite.Functions.FunctionRuntimeTreeNode.GetValue(FunctionContextContainer contextContainer)
   --- End of inner exception stack trace ---
   at Composite.Functions.FunctionRuntimeTreeNode.GetValue(FunctionContextContainer contextContainer)
   at Composite.Renderings.Page.PageRenderer.ExecuteEmbeddedFunctions(XElement element, FunctionContextContainer contextContainer)

Listing 4: Error text

It reads like a lot of gibberish until you look a little bit closer and see the Missing parameter 'videocode' - hey! that is our variable! And it is missing. Right, we have not specified it yet. This is because we had already inserted our function before it had any input parameters.

Specifying input parameters for a function

Select the green box of your function on the page and click the function Properties button (or right-click the green box). Now you will have to specify your videocode.

Or better yet, remove your function and insert it again. When you insert it you will see that it automatically prompts for the missing videocode parameter. This is how the editors will now work with the function.

Figure 17: The function prompting for the required parameter

If there is no default value for a parameter, the function will automatically prompt for it. Note the names of the label and help. The videocode parameter is only used in the function itself. (Sorry, my help text is a bit confusing in here mentioning movie id, which should be a video code.)

Document your functions

You can also give a description for the whole function:

  • Go to the settings tab of your function and type some text in there.

Figure 18: Providing a description for the function

Figure 19: The function shows its description

Generate documentation on functions

You can also generate automatic information of all your functions. C1 CMS will list all the descriptions, different parameters and help text for all the functions. So it is a very good practice to put some text in there for both your editors and for documentation.

To generate documentation for the functions:

  1. From the Function perspective, select All functions.
  2. Click Generate Documentation on the toolbar.

Similarly, you can do with All widget functions. You might as well generate on a single function or a namespace with a number of functions in a similar manner.

More parameters

If you look at the object embed code, you see there are more parameters in there. You can also turn some of these parameters into input parameters of the function, just as you did with the videocode parameter.

<embed 
src="http://www.youtube.com/v/CVvC80xoWmI" type="application/x-shockwave-flash" 
allowscriptaccess="always" 
allowfullscreen="true" 
width="425" 
height="344" />

Listing 5: Parameters of the embed element

To something like:

<object width="{$width}" height="{$height}">
  <param name="movie" value="http://www.youtube.com/v/{$videocode}" />
  <param name="allowFullScreen" value="{$allowfullscreen}" />
  <param name="allowscriptaccess" value="always" />
  <embed src="http://www.youtube.com/v/{$videocode}"
  width="{$width}" height="{$height}"
  movie="http://www.youtube.com/v/{$videocode}" type="application/x-shockwave-flash"
  allowFullScreen="{$allowfullscreen}" allowscriptaccess="always" />
</object>

Listing 6: Implementing and using more parameters

You will have to think about what it would be nice to specify and what it would not.

More parameters do make your functions more flexible, but using too many of them will make them harder to use for editors. When implementing more parameters, it makes much sense to use default values so that the editors have to specify as fewer values as possible.

Also think about the types of parameters, don’t stick with strings, and use Booleans and integers where possible. It will prevent you from getting wrong values. C1 CMS is heavy on strong typing, preventing many errors and bugs before they might occur.

Default value parameter

To create a default value, do the same as you did with the test value. It makes sense to do so except for the very minimum of default parameters that need to be specified by the user. By not specifying a default value, you force it to be specified by the user. In this case, I would specify default parameters for all the additional parameters you might choose to add and only leave the default value for the videocode unspecified.

More uses of an XSLT function without XML

We used all except for the Function calls tab. This tab is actually a very important tab you will use in many XSLT functions except for those functions where you don’t need to get data from the C1 CMS repository.

Most functions will use the Function calls section, they do so to get content from somewhere and then transform the xml with the XSLT. You will learn this in other documents on XSLT functions.

Templates and XHTML includes

Another good example of using XSLT functions, like we did without using the XML function, is for including XHTML in templates. When you work with templates, you will often find pieces of HTML, which are the same in several templates (like CSS and JavaScript includes, disclaimers, headers, footers, web statistics scripts, Google analytics etc). In those cases, it is good to put that HTML in one place, instead of having it in x places (x templates). It means that you will most likely put the HTML in the XSLT function (the way we started out) and add the function to the templates.

Some mightview this as a “downside”:

  • they want to change something in the HTML
  • open the template
  • find out the code is not there
  • need to go to the function and edit it there

But this it is not a downside!

It is true, you will have to take a few extra steps, but:

  • you change it for all x templates at once
  • it prevents you from forgetting a single template
  • it prevents you from ending up with different pieces where you actually want is one!

So it is a good practice to make your code better to manage!