Nibble

Archive for April, 2008

Creating members programmatically 46

Maybe you want to import a number of members or create a custom registration form. You can use the umbraco api to create, update and delete members

I’ll first create a ‘demo’ member type and add 2 properties.

image

Address (alias address) and City (alias city) both of the type textstring.

Owkey now I am ready to write some c# code that will create a new member.

Before I can access the umbraco member api I need to reference cms.dll and businesslogic.dll (these can be found in the bin folder of umbraco).

Now I’ll add a new usercontrol to my project where a member can register. With a couple of textboxes and a button.

image

So the code I need to execute on the click event of the button is:

first add this at the top

using umbraco.cms.businesslogic.member;
using umbraco.cms.businesslogic.propertytype;

And on the click event:

if (Member.GetMemberFromEmail(txtEmail.Text) == null)
{
                MemberType demoMemberType = new MemberType(1040); //id of membertype ‘demo’
                Member newMember = Member.MakeNew(txtName.Text, demoMemberType, new umbraco.BusinessLogic.User(0));
 
                newMember.Email = txtEmail.Text;
                newMember.Password = txtPassword.Text;
                newMember.LoginName = txtUsername.Text;
 
                newMember.getProperty(“address”).Value = txtAddress.Text; //set value of property with alias ‘address’
                newMember.getProperty(“city”).Value = txtCity.Text; //set value of property with alias ‘city’
 
                newMember.Save();
}
else
{
                //member exists
}

 

First I check if there is no other member with the email address, if the email address is not used yet I can make a new member.

Demo project: download

Certified umbraco professional, it’s official ! 6

I’ve just completed the level 1 and level 2 certification test and I can officialy call myself certified professional !

cert

I’ve been in the umbraco community for more then a year now (since I went to the first umbraco course) and I must say I had a blast ! Can’t wait to see what the future will bring.

XSLT formatting dates 6

Recently I needed to get a date in this format : April 19th 2008

Getting a format like ‘April 19 2008′ is easy, you can just use the umbraco library method FormatDateTime. But to get to the ‘April 19th 2008′ format I needed to write a some extra xslt.

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE xsl:Stylesheet [ &lt;!ENTITY nbsp “&#x00A0;”> ]>
<xsl:stylesheet
version=”1.0″
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
xmlns:msxml=”urn:schemas-microsoft-com:xslt”
xmlns:umbraco.library=”urn:umbraco.library”
exclude-result-prefixes=”msxml umbraco.library”>
 
 
<xsl:output method=”xml” omit-xml-declaration=”yes”/>
 
<xsl:param name=”currentPage”/>
 
<xsl:template match=”/”>
 
<!– The fun starts here –>
 
<xsl:for-each select=”$currentPage/node [string(data [@alias=’umbracoNaviHide’]) != ‘1′]”>
<xsl:variable name=”day” select=”substring(@createDate,9,2)” />
 
<xsl:choose>
<xsl:when test=”$day = ‘01′ or $day = ‘21′”>
<xsl:value-of select=”umbraco.library:FormatDateTime(@createDate,’MMMM d’)”/>st <xsl:value-of select=”umbraco.library:FormatDateTime(@createDate,’yyyy’)”/>
 
</xsl:when>
<xsl:when test=”$day = ‘02′ or $day = ‘22′”>
<xsl:value-of select=”umbraco.library:FormatDateTime(@createDate,’MMMM d’)”/>nd <xsl:value-of select=”umbraco.library:FormatDateTime(@createDate,’yyyy’)”/>
 
</xsl:when>
<xsl:when test=”$day = ‘03′ or $day = ‘23′”>
<xsl:value-of select=”umbraco.library:FormatDateTime(@createDate,’MMMM d’)”/>rd <xsl:value-of select=”umbraco.library:FormatDateTime(@createDate,’yyyy’)”/>
 
</xsl:when>
<xsl:otherwise>
<xsl:value-of select=”umbraco.library:FormatDateTime(@createDate,’MMMM d’)”/>th <xsl:value-of select=”umbraco.library:FormatDateTime(@createDate,’yyyy’)”/>
</xsl:otherwise>
</xsl:choose>
 
</xsl:for-each>
 
 
</xsl:template>
 
</xsl:stylesheet>

First I created a variable day that retrieves the day out of the createdate and then depending on wich day it is I add ’st’, ‘nd’, ‘rd’ or ‘th’.

Umbraco Content Picker Datatype 3

Umbraco has a bunch of default data types. One of them is the content picker. You can find the data types in the developer section of umbraco. When you are unfamiliar with umbraco basics like document types and data types, read this great article on the official umbraco blog http://umbraco.org/blog/2007/12/3/dec-3-umbraco-basics-document-types

So when do you use the content picker datatype, lets say you have a site which has a listing of staff members and on your homepage you want to display a ’staff member of the month’. So on your homepage document types you create a new property ’staff member of the month’ and choose ‘Content Picker’  as Type.

When you go to the content and select your homepage you will have the option to select the ’staff member of the month’. When clicking on choose a new window will open with a treeview of the content and there you only need navigate and select the ’staff member’.

image 

 

After saving the document, the nodeid of the staff member will be saved as ’staff member of the month’. So to display this on our homepage we need to write a little xslt. Because a <?UMBRACO_GETITEM field=”#staffmemberofthemonth”/> will only display the nodeid.

<?xml version=”1.0″ encoding=”UTF-8″?>

<!DOCTYPE xsl:Stylesheet [ &lt;!ENTITY nbsp “&#x00A0;”> ]>

<xsl:stylesheet

version=”1.0″

xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”

xmlns:msxml=”urn:schemas-microsoft-com:xslt”

xmlns:umbraco.library=”urn:umbraco.library”

exclude-result-prefixes=”msxml umbraco.library”>

 

 

<xsl:output method=”xml” omit-xml-declaration=”yes”/>

 

<xsl:param name=”currentPage”/>

 

<xsl:template match=”/”>

<a href=”{umbraco.library:NiceUrl($currentPage/data [@alias = ’staffmemberofthemonth’])}”>

<xsl:value-of select=”umbraco.library:GetXmlNodeById($currentPage/data [@alias = ’staffmemberofthemonth’])/@nodeName”/>

</a>

</xsl:template>

 

</xsl:stylesheet>

So $currentPage/data [@alias = ’staffmemberofthemonth’] will get the nodeid of our staff member and with the umbraco library method GetXmlNodeById we can get the xml of the node and have acces to its properties.

Quick tip - Rich text editor and line breaks 3

I have had several editors asking me this:

“When I hit enter I create a new paragraph but I just want a line break”

Solution: when you want to insert a line break you hit shift enter

XSLT List x most recent documents 4

Something you see on loads of site homepages is a list of the x most recent newsitems.

In the umbraco backend you would have a structure simular to this example:

xslt

A Homepage with different types of documents underneath and somewhere in that underlying structure you will also have newsitems documents.

So how do we get a list of the 5 most recent newsitems on the homepage.

Take a look at the example below, I started from the “list sub pages from current page template” in umbraco and added a couple of lines.

First I created a variable that will hold the number of items to display. Then I adjusted the select in the for-each loop to only get the child nodes of NewsPage documents.

Next I sort the items on createDate and the final code I added is an if condition to check if the current position in the loop is lower or equal to the variable (itemsToDisplay).

 

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE xsl:Stylesheet [ &lt;!ENTITY nbsp “&#x00A0;”> ]>
<xsl:stylesheet
version=”1.0″
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
xmlns:msxml=”urn:schemas-microsoft-com:xslt”
xmlns:umbraco.library=”urn:umbraco.library”
exclude-result-prefixes=”msxml umbraco.library”>
 
 
<xsl:output method=”xml” omit-xml-declaration=”yes”/>
 
<xsl:param name=”currentPage”/>
 
<xsl:variable name=”itemsToDisplay” select=”5″ />
 
<xsl:template match=”/”>
 
<!– The fun starts here –>
<ul>
<xsl:for-each select=”$currentPage/descendant::node [@nodeTypeAlias = ‘NewsPage’]/node”>
<xsl:sort select=”@createDate” order=”descending”/>
 
<xsl:if test=”position() &lt;= $itemsToDisplay”>
<li>
<a href=”{umbraco.library:NiceUrl(@id)}”>
<xsl:value-of select=”@nodeName”/>
</a>
</li>
</xsl:if>
</xsl:for-each>
</ul>
 
</xsl:template>
 
</xsl:stylesheet>

.net usercontrols and the umbraco dictionary 11

With umbraco it is possible to create multilingual site. I’m not going to get into details on how to set this up (not in this post), but when you want to localize your templates and macro’s you need to create dictionary items. Your .net usercontrols can also use the umbraco dictionary.

You manually create a new dictionary item and then set the control’s text to the dictionary item (after referencing the needed assemblies).

MyControl.Text = umbraco.library.GetDictionaryItem(“mydictionaryitem”);
MySecondControl.Text = umbraco.library.GetDictionaryItem(“anotherdictionaryitem”);

 

This is owkey when you have a small usercontrol and don’t have to put in loads of dictionary items.

But image what a lousy task it would  be if you had 30,40, more controls on your usercontrol (creating all the dictionary items manually).

So to save me time I wrote some code that loops all controls in a usercontrol and sets the text of the control.

I created a base usercontrol class which inherits from the usercontrol class. And I make my usercontrols inherit from my base class.

This Is my BaseUserControl class:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using umbraco.cms.businesslogic;
 
namespace TG.Umb.Library
{
    public class BaseUserControl: UserControl
    {
        private string _dictionaryId;
 
        protected void Page_Load(object sender, EventArgs e)
        {

            if (Request[“addtodictionary”] != null)
            {
                //create dictionary items

                createDictionaryItems(this.Controls);
                Response.Write(“Dictionary Items Created”);
            }
 
            if (!IsPostBack)
            {
                //set copy of controls
                setCopy(this.Controls);
            }
        }
 
        #region UmbracoDictionaryFunctions
 
        //loop all controls and set text
        public void setCopy(ControlCollection Controls)
        {
 
            foreach (Control ctrl in Controls)
            {
 
 
                if (ctrl is System.Web.UI.WebControls.Panel)
                {
                    setCopy(ctrl.Controls);
                }
 
                if (ctrl is System.Web.UI.WebControls.Literal)
                {
                    if (umbraco.library.GetDictionaryItem(dictionaryId + ((Literal)ctrl).ID) != string.Empty)
                    {

                        ((Literal)ctrl).Text = umbraco.library.GetDictionaryItem(dictionaryId + ((Literal)ctrl).ID);
                    }
                }
 
                if (ctrl is System.Web.UI.WebControls.HyperLink)
                {
                    if (umbraco.library.GetDictionaryItem(dictionaryId + ((HyperLink)ctrl).ID) != string.Empty)
                    {
                        ((HyperLink)ctrl).Text = umbraco.library.GetDictionaryItem(dictionaryId + ((HyperLink)ctrl).ID);
                    }
                }
 
                if (ctrl is System.Web.UI.WebControls.Button)
                {
                    if (umbraco.library.GetDictionaryItem(dictionaryId + ((Button)ctrl).ID) != string.Empty)
                    {
                        ((Button)ctrl).Text = umbraco.library.GetDictionaryItem(dictionaryId + ((Button)ctrl).ID);
                    }

                }
 
                if (ctrl is System.Web.UI.WebControls.CheckBox)
                {
                    if (umbraco.library.GetDictionaryItem(dictionaryId + ((CheckBox)ctrl).ID) != string.Empty)
                    {
                        ((CheckBox)ctrl).Text = umbraco.library.GetDictionaryItem(dictionaryId + ((CheckBox)ctrl).ID);
                    }
                }
            }
        }
 
        //loop all controls and create dictionary Item
        public void createDictionaryItems(ControlCollection Controls)
        {
            foreach (Control ctrl in Controls)
            {

                if (ctrl is System.Web.UI.WebControls.Panel)
                {
                    createDictionaryItems(ctrl.Controls);
                }
 

                if (ctrl is System.Web.UI.WebControls.Literal)
                {
                    createDictionaryItem(dictionaryId + ((Literal)ctrl).ID, ((Literal)ctrl).Text);
                }
 
                if (ctrl is System.Web.UI.WebControls.HyperLink)
                {
                    createDictionaryItem(dictionaryId + ((HyperLink)ctrl).ID, ((HyperLink)ctrl).Text);
                }
 
                if (ctrl is System.Web.UI.WebControls.Button)
                {
                    createDictionaryItem(dictionaryId + ((Button)ctrl).ID, ((Button)ctrl).Text);
                }
 
                if (ctrl is System.Web.UI.WebControls.CheckBox)
                {
                    createDictionaryItem(dictionaryId + ((CheckBox)ctrl).ID, ((CheckBox)ctrl).Text);
                }
            }
        }
 

        //create dictionaryItem
        private void createDictionaryItem(string name, string defaulttext)
        {
            try
            {
 
                Dictionary.DictionaryItem.addKey(name, defaulttext);

                Response.Write(“added “ + name + “<br/>”);
            }
            catch
            {
                //allready exists
            }
        }
 

        //identifier for umbraco dictionary
        //string dictionaryId = “frmLoginLogout”;
        public string dictionaryId
        {
            get
            {
 
                return _dictionaryId;


            }
            set
            {
                _dictionaryId = value;
            }
        }
 
        #endregion
    }
}
 

 

So all I need to do in my usercontrols is:

public partial class frmEditProfile : BaseUserControl
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            base.dictionaryId = this.GetType().Name;
            base.Page_Load(sender, e);
 
        }
    }

 

Inherit from the custom class instead of UserControl, set the dictionaryId and cal the page_load of the base class.

Now the next step is to trigger the usercontrol to loop its controls and add dictionary items.

You can do this by adding ?addtodictionary=true to the querystring on the page where you have your usercontrol.

So if you have a page http://www.examplesite.com/page.aspx you request http://www.examplesite.com/page.aspx?addtodictionary=true

And *boom* the dictionary items get created automaticly. This is an example of the dictionary items created:

dictionary

So the name will start with the usercontrol name followed by the control id;

Now you can start setting the correct copy for the dictionary items…

And as you will notice the text will be fetched from the dictionary.

The loops in the class will only work on  literal, hyperling, button and checkbox, you can add other types of controls in the loops.

BaseUserControl class: download

Umbraco and windows live writer 14

Since version 3 of umbraco, umbraco supports windows live writer. For those who don’t know how to set things up, here is a short howto based on my experience.

Go to the users section in umbraco

Select for which user you want to enable this ( or create a new one) , so just select your user from the tree.

WindowsLiveWriter_Umbracoandwindowslivewriter_9AB7_image_4

As you will see since v3 there are now 2 tab pages. One has the name of your user and the other is named content channel.

The content channel tab is the place where you need to do the configuration.

  • Name: this will be the name of the content channel
  • Start Node in Content : Here you need to select the parent node, the documents will be published under this node
  • Search all children : this is a checkbox, check this if you want to search the entire structure and not just the first level children
  • Star Node in Media Library: haven’t tested this but i think this will be the node where the media from your posts will be saved, this isn’t a mandatory item , so just leaving it without choosing an item will work
  • Document Type: Here you need to select what the document type of the post you are going to make is. So  if you have a document type ‘blog post’ and you want to be making blog post documents from inside live writer you will need to select ‘blog post’
  • Description Field: This is the property of the document type where you want to store the content
  • Category Field: This is the property of the document type where you want to store the categories
  • Excerpt Field: Haven’t tested this ( not mandatory ) but I think this will fill up the property with a small excerpt of your content

 

WindowsLiveWriter_Umbracoandwindowslivewriter_9AB7_image_6

So this takes care of the umbraco side of things, now how to set up live writer.

So start live writer and choose weblog/ add weblog account.

This will start the add weblog wizard, the first form you will see is this:

WindowsLiveWriter_Umbracoandwindowslivewriter_9AB7_image_16

Here you need to select Another weblog service. Next step is to setup the credentials

WindowsLiveWriter_Umbracoandwindowslivewriter_9AB7_image_10

Weblog homepage url: this is just the url of your website ( like http://www.examplesite.com )

Username: this needs to be the login of the umbraco user where you set up the content channel earlier

Password: the password of the user

On to the next step.

WindowsLiveWriter_Umbracoandwindowslivewriter_9AB7_image_14

The provider umbraco uses is the Metaweblog API

The remote posting Url needs to be like this :

http://www.examplesite.com/umbraco/channels.aspx

So the final step is to approve the settings

WindowsLiveWriter_Umbracoandwindowslivewriter_9AB7_image_18

Why Umbraco Rocks - Adding custom usercontrols 18

Umbraco rocks! Why ?

Reason one:

It’s extremely easy to add custom .net usercontrols to your umbraco site. So you can still take full advantage of the .net framework when working with umbraco. I made a quick screencast showing how to add a .net usercontrol to your umbraco site.

 

image

Demo Project: download

Xslt Paging example 36

Default umbraco has a bunch of xslt templates you can choose from when creating a new xslt file, for me about 80% of the time I start from a template and adjust it to my needs. But one thing that is missing is an example of paging, so for those of you who would like to know how to add paging to a list, check out the examples below. To change the number of items displayed just change the recordsPerPage variable. I started from the “list sub pages from current page template” in umbraco and added 2 examples with paging below (one with only a previous and a next link and another example that also adds page numbers).

 

Without paging ( List Sub Pages From Current Page template )

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE xsl:Stylesheet [ &lt;!ENTITY nbsp “&#x00A0;”> ]>
<xsl:stylesheet
version=”1.0″
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
xmlns:msxml=”urn:schemas-microsoft-com:xslt”
xmlns:umbraco.library=”urn:umbraco.library”
exclude-result-prefixes=”msxml umbraco.library”>
 
 
<xsl:output method=”xml” omit-xml-declaration=”yes”/>
 
<xsl:param name=”currentPage”/>
 
<xsl:template match=”/”>
 
<!– The fun starts here –>
<ul>
<xsl:for-each select=”$currentPage/node [string(data [@alias=’umbracoNaviHide’]) != ‘1′]”>
<li>
<a href=”{umbraco.library:NiceUrl(@id)}”>
<xsl:value-of select=”@nodeName”/>
</a>
</li>
</xsl:for-each>
</ul>
 
</xsl:template>
 
</xsl:stylesheet>

 

With paging ( previous + next )

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE xsl:Stylesheet [ &lt;!ENTITY nbsp “&#x00A0;”> ]>
<xsl:stylesheet
version=”1.0″
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
xmlns:msxml=”urn:schemas-microsoft-com:xslt”
xmlns:umbraco.library=”urn:umbraco.library”
exclude-result-prefixes=”msxml umbraco.library”>
 
 
<xsl:output method=”xml” omit-xml-declaration=”yes”/>
 
<xsl:param name=”currentPage”/>
 
<xsl:template match=”/”>
 
<xsl:variable name=”recordsPerPage” select=”1″/>
 
<xsl:variable name=”pageNumber” >
<xsl:choose>
<!– first page –>
<xsl:when test=”umbraco.library:RequestQueryString(’page’) &lt;= 0 or string(umbraco.library:RequestQueryString(’page’)) = ” or string(umbraco.library:RequestQueryString(’page’)) = ‘NaN’”>0</xsl:when>
<!– what was passed in –>
<xsl:otherwise>
<xsl:value-of select=”umbraco.library:RequestQueryString(’page’)”/>
</xsl:otherwise>
</xsl:choose>
 
</xsl:variable> &nbsp;
 
<xsl:variable name=”numberOfRecords” select=”count($currentPage/node)”/>
 
<!– The fun starts here –>
<ul>
<xsl:for-each select=”$currentPage/node [string(data [@alias=’umbracoNaviHide’]) != ‘1′]”>
<xsl:if test=”position() &gt; $recordsPerPage * number($pageNumber) and
position() &lt;= number($recordsPerPage * number($pageNumber) +
$recordsPerPage )">
<li>
<a href=”{umbraco.library:NiceUrl(@id)}”>
<xsl:value-of select=”@nodeName”/>
</a>
</li>
</xsl:if>
</xsl:for-each>
</ul>
 
<xsl:if test=”$pageNumber &gt; 0″>
<a href=”?page{$pageNumber -1}”>previous </a>
</xsl:if>
 
<xsl:if test=”(($pageNumber +1 ) * $recordsPerPage) &lt; ($numberOfRecords)”>
<a href=”?page={$pageNumber +1}”>next</a>
</xsl:if>
</xsl:template>
 
</xsl:stylesheet>

 

With paging ( previous + page numbers + next )

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE xsl:Stylesheet [ &lt;!ENTITY nbsp “&#x00A0;”> ]>
<xsl:stylesheet
version=”1.0″
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
xmlns:msxml=”urn:schemas-microsoft-com:xslt”
xmlns:umbraco.library=”urn:umbraco.library”
exclude-result-prefixes=”msxml umbraco.library”>
 
 
<xsl:output method=”xml” omit-xml-declaration=”yes”/>
 
<xsl:param name=”currentPage”/>
 
<xsl:template match=”/”>
 
<xsl:variable name=”recordsPerPage” select=”1″/>
 
<xsl:variable name=”pageNumber” >
<xsl:choose>
<!– first page –>
<xsl:when test=”umbraco.library:RequestQueryString(’page’) &lt;= 0 or string(umbraco.library:RequestQueryString(’page’)) = ” or string(umbraco.library:RequestQueryString(’page’)) = ‘NaN’”>0</xsl:when>
<!– what was passed in –>
<xsl:otherwise>
<xsl:value-of select=”umbraco.library:RequestQueryString(’page’)”/>
</xsl:otherwise>
</xsl:choose>
 
</xsl:variable> &nbsp;
 
<xsl:variable name=”numberOfRecords” select=”count($currentPage/node)”/>
 
<!– The fun starts here –>
<ul>
<xsl:for-each select=”$currentPage/node [string(data [@alias=’umbracoNaviHide’]) != ‘1′]”>
<xsl:if test=”position() &gt; $recordsPerPage * number($pageNumber) and
position() &lt;= number($recordsPerPage * number($pageNumber) +
$recordsPerPage )">
<li>
<a href=”{umbraco.library:NiceUrl(@id)}”>
<xsl:value-of select=”@nodeName”/>
</a>
</li>
</xsl:if>
</xsl:for-each>
</ul>
 
<xsl:if test=”$pageNumber &gt; 0″>
<a href=”?page{$pageNumber -1}”>previous </a>
</xsl:if>
 
<xsl:call-template name=”for.loop”>
<xsl:with-param name=”i”>1</xsl:with-param>
<xsl:with-param name=”page” select=”$pageNumber +1″></xsl:with-param>
<xsl:with-param name=”count” select=”ceiling(count($currentPage/node)div $recordsPerPage)”></xsl:with-param>
</xsl:call-template>
 
<xsl:if test=”(($pageNumber +1 ) * $recordsPerPage) &lt; ($numberOfRecords)”>
<a href=”?page={$pageNumber +1}”>next</a>
</xsl:if>
</xsl:template>
 
<xsl:template name=”for.loop”>
 
<xsl:param name=”i”/>
<xsl:param name=”count”/>
<xsl:param name=”page”/>
<xsl:if test=”$i &lt;= $count”>
 
<xsl:if test=”$page != $i”>
<a href=”{umbraco.library:NiceUrl($currentPage/@id)}?page={$i - 1}” >
 
<xsl:value-of select=”$i” />
</a>
</xsl:if>
 
<xsl:if test=”$page = $i”>
 
<xsl:value-of select=”$i” />
 
</xsl:if>
 
 
</xsl:if>
<xsl:if test=”$i &lt;= $count”>
<xsl:call-template name=”for.loop”>
<xsl:with-param name=”i”>
<xsl:value-of select=”$i + 1″/>
</xsl:with-param>
<xsl:with-param name=”count”>
<xsl:value-of select=”$count”/>
</xsl:with-param>
<xsl:with-param name=”page”>
<xsl:value-of select=”$page”/>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

Next Page »