Monday, August 30, 2010

Recursive XSL Templates

I am re-posting my article once published in code project in 2006. This brief article will demonstrate the recursive nature of templates. For original posting click here.
For source code download click here.
Output Needed:



Introduction

XSL is a declarative programming language. Variables that are once declared cannot be reassigned. It is often difficult for programmers coming from procedural languages background to do advanced tasks. Using XSL, we can solve complex problems, which at first glance often seem to be difficult or impossible. In this brief article, I will demonstrate the recursive nature of templates. In a typical case of a product catalog display, our requirement is to display the product details in each cell, and number of columns should be selectable by the user. The sample XML file is listed below:

<data>
<product name="Heine HKL with trolleystand" weight="34.4kg" price="230.45">
<product name="Universal clamp and Projector" weight="10.64kg" price="670.45">
<product name="Examination Lamp, Universal Mount" weight="1.08kg" price="25.45">
<product name="Provita Examination Lamp, Mobile Base" weight="1.4kg" price="215.45">
<product name="35Watt Flexible Arm Light to fit Rail system" weight="11.67kg" price="130.45">
.
.
.
.
.
.
</data>


Assuming we are getting the above from a business component, each element row corresponds to a product, whose attributes comprises of product specific data. Each product along with its details will be rendered in a single cell. And the number of columns should be definable at runtime. Following is the brief XSL which does the rendering:


<xml:namespace prefix = xsl />0">
<tr>
<xsl:apply-templates select="">=
$startindex and position() < ($startindex+$numofCols)]" mode="rows"> </xsl:apply-templates> </tr> <xsl:call-template name="renderColumns"> <xsl:with-param name="listrows" select="">= $startindex+$numofCols]"></xsl:with-param>
<xsl:with-param name="startindex" select="$startindex"></xsl:with-param>
<xsl:with-param name="numofCols" select="$numofCols"></xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>

<xsl:template match="node()" mode="rows">
<td nowrap="true">
<table style="BORDER-BOTTOM: thin solid; BORDER-LEFT: thin solid; WIDTH: 100%; BORDER-TOP: thin solid; BORDER-RIGHT: thin solid">
<xsl:apply-templates select="@*"></xsl:apply-templates>
<tbody></tbody></table>
</td>
</xsl:template>

<xsl:template match="@*">
<tr>
<td style="TEXT-TRANSFORM: uppercase; BACKGROUND-COLOR: gainsboro; FONT-SIZE: larger">
<xsl:value-of select="name()"></xsl:value-of>
</td>
<td>
<xsl:value-of select="."></xsl:value-of>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>

Explanation

<xsl:template match="/">
<xsl:param name="numCols" select="3"></xsl:param>


As would a C or C++ programmer organize and reuse the code using functions or object methods, in XSL, we can organize code using templates. The above code is the root template which will be invoked by the XSLT processor. We are declaring a parameter using xsl:param, whose name is numCols. The user can pass this parameter; if the user is not supplying any value in this parameter, then, by default, it will have a value of 3. This variable will specify the number of columns to be rendered.

<xsl:call-template name="renderColumns">
<xsl:with-param name="listrows" select="//product"></xsl:with-param>
<xsl:with-param name="startindex" select="1"></xsl:with-param>
<xsl:with-param name="numofCols" select="$numCols"></xsl:with-param>
</xsl:call-template>

We are calling the renderColumns template, to which we are passing three parameters. In listrows, we are selecting all product elements, startindex signifies the starting index, and numofCols will control the number of rows to be rendered.

<xsl:template name="renderColumns">
<xsl:param name="listrows"></xsl:param>
<xsl:param name="startindex"></xsl:param>
<xsl:param name="numofCols"></xsl:param>
<xsl:if test="">0">
<tr>
<xsl:apply-templates select="">=
$startindex and position() < ($startindex+$numofCols)]" mode="rows">
</xsl:apply-templates>
</tr>
<xsl:call-template name="renderColumns">
<xsl:with-param name="listrows" select="">= $startindex+$numofCols]"></xsl:with-param>
<xsl:with-param name="startindex" select="$startindex"></xsl:with-param>
<xsl:with-param name="numofCols" select="$numofCols"></xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>

In the XSL template renderColumns, we are selecting the elements whose position will be greater than or equal to the starting index and whose position is less than or equal to the sum of startindex and numofcols. After rendering these subset of elements, we are recursively calling renderColumns by selecting a subset of elements whose position is greater than the sum of startindex and numofCols, which are already rendered. For exiting this recursive loop, we have a test condition at the start which checks for the count of elements in the listrows variable. As we are selecting only those elements which are yet to be rendered while calling recursively, the set of nodes by each call will be reduced by the number of elements rendered. For rendering rows, in this call template, we are using the following template:

<xsl:template match="node()" mode="rows">
<td nowrap="true">
<table style="BORDER-BOTTOM: thin solid; BORDER-LEFT: thin solid; WIDTH: 100%; BORDER-TOP: thin solid; BORDER-RIGHT: thin solid">
<xsl:apply-templates select="@*"></xsl:apply-templates>
<tbody></tbody></table>
</td>
</xsl:template>

in which we are converting the attribute nodes into elements and calling another template:

<xsl:template match="@*">
<tr>
<td style="TEXT-TRANSFORM: uppercase; BACKGROUND-COLOR: gainsboro; FONT-SIZE: larger">
<xsl:value-of select="name()"></xsl:value-of>
</td>
<td>
<xsl:value-of select="."></xsl:value-of>
</td>
</tr>
</xsl:template>

which does the job of rendering the product details in a cell.

Conclusion

Even though variables are constants through out the life time of a variable in XSL, we can achieve things which, at first glance, look impossible due to the declarative nature of XSL. Upon close look and thinking in a declarative manner, we can solve the problem.

Wednesday, August 25, 2010

Design Patterns by Metaphors - Part I (Creational Patterns)

From today, I am starting blog series on Design Patterns. There are numerous technical posts, material on this subject out there awaiting just googling to get discovered. So I don't want to repeat same here. What I will be trying to do is explain them using metaphors, in layman terms, so that newbies can understand easily and can adapt them with ease.

I will start with Creational Patterns.

Creational Patters:

Are patterns which guides you in tackling object creation challenges in certain scenarios.

Abstract Factory:




Simpson lives in world of SONY. Every electronic appliance in his world is of SONY. But he wants agility to move to other electronic worlds as well, may be Samsung in future. In order for him to able to move to different worlds without much effort, he uses remote covers over top of particular remote to access functionality. All remotes in electronics will support that cover. Tomorrow even if he changes to Samsung, he will still be able to use them with his cover.
Due to this common cover fitting all remotes to access only common minimum features, he will not be able to access any special button which might be specific to a particular remote. He trades this for flexibility to be able to move to different worlds.

Builder Pattern




Result is so varied that we do not have common interface for end result. In case of Abstract Factory we had common interface for end result.
User Will provide which builder to use to Director.

Factory Method




Whenever Simpson requests for car to Car Factory, he will always get latest car available at that time, wrapped under Car prototype cover. As time evolves, as new models gets added, he still gets latest models but wrapped in car prototype. He will get latest engine performance, latest ABS, latest electronics working under hood.
But all cars are wrapped under car prototype, which has only minimum control points. Though he can experience latest engine performance with car prototypes accelerator, he cannot access to car GenX’s latest Blue Me feature as that is wrapped under car prototype.

Abstract vs Factory


Thanks to David Hayden for making it so clear in his post at here.

Singleton

Monday, August 16, 2010

Silverlight - Property Value Synchronization between Two View Models

Recently I had been confronted with a design issue to keep two property values in two different View Models in Sync.



It is a simple issue, where you can subscribe to PropertyChange notifications and detect whenever interested property changes in Object1, set AnotherProperty's value in Another Object. And vice versa. To avoid recursive infinite loop situation, you can keep a flag which tracks direction of change and avoids this infinite loop.

But I wanted to solve this by keeping following constratints

1. I need to reuse this syncing logic wherever required in future.
2. Loosely Coupled.
3. No reflection, I want compile time support to detect any errors or most of them.
4. Should support FluentAPI for better usability.

Few assumption I made are
4. Both objects implements INotifyPropertyChanged event which raises event change notifications whenever property is changed.

Before discussing code, once developed you can use it like following to keep both objects in Sync.


//ViewModel which has a property
Class1 orgViewModel = new Class1();
//Another ViewModel which has another property.
Class2 anotherViewModel = new Class2();
//Sync API will be exposed by this SyncClass Which takes ViewModel types and property type.
SyncClass SyncClass = new SyncClass();

//Configure ViewModel with predicate to detect when property is changed and provide functions to read and write property values.
SyncClass.MonitorClass(orgViewModel, (propname) => { return propname == "MyVal"; })
.SetGetValue(()=>orgViewModel.MyVal)
.SetSetValue((i)=>orgViewModel.MyVal=i);
//Configure another ViewModel with predicate to detect when property is changed and provide functions to read and write property values.
SyncClass.MonitorAnotherClass(anotherViewModel, (propname) => { return propname == "AnotherVal"; })
.SetGetValue(()=>anotherViewModel.AnotherVal)
.SetSetValue((i1)=>anotherViewModel.AnotherVal=i1);
//Start Synchronization.
SyncClass.StartSync();

Once you configure you view models and property in above manner SynClass will auto sync two properties.

Code Listing

delegate void ValueChanged(object sender,EventArgs e);

class UsingClass
{
bool IsOriginator = false;
public event ValueChanged ObjectValueChanged;

T _MonitorObject;
Func _GetValue;
Action _SetValue;
Func<string,bool> _IsPropChanged;
public UsingClass(T MonitorObject,Func<string,bool> IsPropertyChanged)
{
_IsPropChanged = IsPropertyChanged;
_MonitorObject = MonitorObject;
INotifyPropertyChanged propChanged = _MonitorObject as INotifyPropertyChanged;
if (propChanged != null)
{
propChanged.PropertyChanged += (o1, e1) =>
{
if (_IsPropChanged(e1.Proeprtyname))
{
this.IsOriginator = true;
if (this.ObjectValueChanged != null)
{
this.ObjectValueChanged(this, new EventArgs());
}
}
};
}

}
public UsingClass SetGetValue(Func GetValue)
{
_GetValue=GetValue;
return this;
}
public T1 GetValue()
{
return _GetValue();
}
public void SetSetValue(Action SetValue)
{
this._SetValue = SetValue;
}
public void SetValue(T1 val1)
{
if (!IsOriginator)
{
_SetValue(val1);
}
else
{
IsOriginator =
false;
}
}
}

class SyncClass
{
UsingClass Object1;
UsingClass Object2;
public UsingClass MonitorClass(T MonitorObject,Func<string,bool> CheckPropertyChanged)
{
Object1 =
new UsingClass(MonitorObject,CheckPropertyChanged);
return Object1;

}
public UsingClass MonitorAnotherClass(T1 MonitorAnotherObject, Func<string, bool> CheckPropertyChanged)
{
Object2 =
new UsingClass(MonitorAnotherObject, CheckPropertyChanged);
return Object2;
}
public void StartSync()
{
Object1.ObjectValueChanged += (o, e) =>
{
Object2.SetValue(Object1.GetValue());
};
Object2.ObjectValueChanged += (o1, e1) =>
{
Object1.SetValue(Object2.GetValue());
};
}

}

I prepared a sample in Console Application which will be easy to execute and see how its working.

Click here to download sample application. You need VS 2010 to open this solution.

Hope you enjoyed this code crunch..