Tuesday, August 26, 2008

XSLT - Keys implementation

XSLT Keys - xsl:key is used to declare keys. If I were to define xsl:key in my lanuage, I would say, key represents a collection of nodes (as specified in use attribute) which is filterd by specific pattern as defined by "match" attribute.

Syntax

<xsl:key name="name" match="pattern" use="expression"/>
Attributes

AttributeValue Description
name name Required. Specifies the name of the key
match pattern Required. Defines the nodes to which the key will be applied
use expression Required. The value of the key for each of the nodes

To explain keys better, let me take help of following example.

Below is a XML structure depicting information about various movies being played at "My Theater" on specific dates along with their show timings.

[code]
<?xml version="1.0" encoding="UTF-8"?>
<showtimes>
<id>my theater</id>
<film>
<name>The Big Show</name>
<show>
<date>06012006</date>
<time>0500</time>
</show>
<show>
<date>06012006</date>
<time>0700</time>
</show>
<show>
<date>06012006</date>
<time>0600</time>
</show>
<show>
<date>03012006</date>
<time>0700</time>
</show>
<show>
<date>08012006</date>
<time>0500</time>
</show>
<show>
<date>08012006</date>
<time>0700</time>
</show>
</film>
<film>
<name>The Truman Show</name>
<show>
<date>09012006</date>
<time>0600</time>
</show>
<show>
<date>09012006</date>
<time>0700</time>
</show>
<show>
<date>09012006</date>
<time>0700</time>
</show>
<show>
<date>08012006</date>
<time>0700</time>
</show>
<show>
<date>03012006</date>
<time>0600</time>
</show>
<show>
<date>03012006</date>
<time>0700</time>
</show>
</film>
</showtimes>
[/code]

Now, if one is to generate output as shown below, it is required that we group shows based on date. Now, to achieve this we would require xsl:key.

[output]

Movie Listings


Name of show : The Big Show
DATE = 03012006 | Show Timings : 0600 0700 0700
DATE = 06012006 | Show Timings : 0500 0600 0700
DATE = 08012006 | Show Timings : 0500 0700 0700

Name of show : The Truman Show
DATE = 09012006 | Show Timings : 0600 0700 0700
[/output]

Analyse the XSLT code to understand the functioning of keys.

[code]
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<--====grouping shows based on date under key with name shows======-->
<xsl:key name="shows" match="show" use="date"/>

<xsl:template match="/">
<html>
<head>
<title>Movie Listings</title>
</head>
<body>
<h1>Movie Listings</h1>
<hr/>
<--====looping for multiple films======-->
<xsl:for-each select="./showtimes/film">
<xsl:if test="position() > 1 ">
<hr/>
</xsl:if>
<xsl:apply-templates select="."/>
</xsl:for-each>
</body>
</html>
</xsl:template>

<xsl:template match="id"/>

<xsl:template match="film">
<div align="center">
<b><xsl:text>Name of show : </xsl:text></b>
<b><xsl:value-of select="self::film/child::name"/></b> <br/>
</div>
<--====fetching show node [who is same as of show node of position 1
when date is union/same]
======-->
<xsl:for-each select="show[count(key('shows', date)[1] | .) = 1]">
<xsl:sort select="substring(date, 5, 4)"/>
<xsl:sort select="substring(date, 1, 2)"/>
<xsl:sort select="substring(date, 3, 2)"/>
<div>
DATE = <xsl:value-of select="date"/><xsl:text> | </xsl:text>
<xsl:text>Show Timings : </xsl:text>
<--====iterating shows from key having specific date======-->
<xsl:for-each select="key('shows', date)">
<xsl:sort select="time"/>
<xsl:value-of select="time"/>
<xsl:if test="position() < last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</div>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
[/code]

Friday, August 22, 2008

XSLT - Modes In Templates

"Modes allow an element to be processed multiple times, each time producing a different result." - [As defined by W3C]
Another way of interpreting modes can be, a mechanism which allows us to process same XML data island(by this I mean XML Node Set) in multiple ways.

To understand modes let us look at example below:

xml fragment
[code]

<?xml version="1.0" encoding="UTF-8"?>
<source>
<AAA id="a1" pos="start">
<BBB id="b1" />
<BBB id="b2" />
</AAA>
<AAA id="a2">
<BBB id="b3" />
<BBB id="b4" />
<CCC id="c1">
<CCC id="c2" />
</CCC>
<BBB id="b5">
<CCC id="c3" />
</BBB>
</AAA>
</source>

[/code]

XSLT snippet here will render XML element "ccc" in different color. Root template guides how child nodes will be processed. Refer the green comments in XSLT code.

[code]
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="/">
<xsl:apply-templates mode="red" />
<xsl:apply-templates mode="blue" />
<xsl:apply-templates />
</xsl:template>

<!--====== override default template to mode specifics ====== -->
<xsl:template match="*" mode="red">
<xsl:apply-templates mode="red"/>
</xsl:template>

<!--====== ccc template to mode specifics ====== -->
<xsl:template match="CCC" mode="red">
<div style="color:red">
parent:<xsl:value-of select="name(parent::*)"/><br/>
<xsl:value-of select="name()" />
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id" />
</div>
<xsl:apply-templates mode="red"/>
</xsl:template>

<!--====== override default template to mode specifics ====== -->
<xsl:template match="*" mode="blue">
<xsl:apply-templates mode="blue"/>
</xsl:template>

<!--====== ccc template to mode specifics ====== -->
<xsl:template match="CCC" mode="blue">
<div style="color:blue">
parent:<xsl:value-of select="name(parent::*)"/><br/>
<xsl:value-of select="name()" />
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id" />
</div>
<xsl:apply-templates mode="blue"/>
</xsl:template>

<xsl:template match="CCC">
<div style="color:purple">
parent:<xsl:value-of select="name(parent::*)"/><br/>
<xsl:value-of select="name()" />
<xsl:text> id=</xsl:text>
<xsl:value-of select="@id" />
</div>
<!-- forcing child ccc element node to be processed as per "red" mode -->
<xsl:apply-templates mode="red"/>
</xsl:template>
</xsl:stylesheet>
[/code]


[output]
parent:AAA
CCC id=c1
parent:CCC
CCC id=c2
parent:BBB
CCC id=c3

parent:AAA
CCC id=c1
parent:CCC
CCC id=c2
parent:BBB
CCC id=c3

parent:AAA
CCC id=c1
parent:CCC
CCC id=c2
parent:BBB
CCC id=c3
[/output]

As one can see, modes help us in multiple processing of same nodes. Looking at the output one may wonder, I can achieve the same using xsl:if why do I need to use mode?
Well, in this condition there is no XML tree which needs to be processed differently, instead what we have here is single XML element "ccc", therefore xsl:if would suffice. However, consider a scenario, where we need to override default template and process a complicated XML tree, in multiple result cases, that is when we would see the relevance of modes.

Cheers

SharePoint : HttpContext in synchronous / asynchronous events

In my previous post we discussed how one can register/unregister event receivers and what are the various events which SharePoint exposes in its Object Model. Let us focus our attention on how one can add custom business logic alongside these events and how to handle page redirects using HttpContext when these events are triggered.
To start with, let me differentiate between synchronous and asynchronous events.

The "...ing" events (synchronous) occurs before the action starts and the "...ed" (asynchronous) occurs after the actions ends.
Synchronous events:
· Occur before the event.
· Block the flow of code execution until your event handler completes.
· Provide you with the ability to cancel the events resulting in no after event (“...ed") being fired.
Asynchronous events:

· Occur after the event.
· Do not block the flow of code execution in SharePoint.


Custom event handler:
[code]
public class MyCustomEventHandler : SPItemEventReceiver
{
public MyCustomEventHandler() { }
public override void ItemAdding(SPItemEventProperties properties) { //your code goes here (synchronous event) }

public override void ItemAdded(SPItemEventProperties properties) { //your code goes here (asynchronous event)
}
}[/code]

Another business scenario maybe, one needs to redirect to a different page once custom code is executed. For redirection, fetching HttpContext is mandatory. Now, HttpContext is available in synchronous events but not in asynchronous events. Refer the code below, to see a workaround how to get HttpContext in Asynchronous events [this i found on SharePoint Kings Blog]:

[code]
public class MyCustomEventHandler:SPItemEventReceiver
{
HttpContext current;
static object obj;
public
MyCustomEventHandler()
{
if (current == null)
{
current = HttpContext.Current;
}
}
public override void ItemAdded(SPItemEventProperties properties)
{
current = (HttpContext)obj;
//your code goes here (asynchronous event)
SPUtility.Redirect("http://server/page.", SPRedirectFlags.Trusted, current);
}
public override void ItemAdding(SPItemEventProperties properties)
{
obj = current;
//your code goes here (synchronous event)
}
[/code]

Cheers

Wednesday, August 20, 2008

SharePoint: Register / Unregister Event Receivers

"Event Receivers" in SharePoint is one topic, I always wanted to discuss and today seems to be a good day to do so.Event Receivers allow you to add your custom/specific business logic/needs into the default functionality of SharePoint. As in, item Added, item Deleted, item Updated, site Created, site Deleted, etc... are few events SharePoint raises and carry out actions based on those events. Now, requirement may arise when, we need to do "something more" when such events are raised by SharePoint.
That "something more" can be:
  • Retrieve information from a database such as filling in the remaining fields of a list based on a CustomerID (assuming you don't have an enterprise license for BDC)
  • Call a web service
  • Start a workflow
  • Perform list data validation
  • Convert document to PDF and store in alternative list.
  • Access data in another list
  • or many other things.
To do this "something more" we need event receivers.

Question arises how does one hook/unhook custom logic to these events. For this refer the code below(code below operates on registering/unregistering events to a SharePoint Document Library):

eventType = SPEventReceiverType.ItemAdding,SPEventReceiverType.ItemDeleted etc...
assemblyName =
ClassName = NameSpace,ClassName

register events
[code]
public static void addEventReceiver(SPList docLib, SPEventReceiverType eventType, string assemblyName, string className)
{
try
{
docLib.EventReceivers.Add(eventType, assemblyName, className);
docLib.Update();
}
catch(Exception ex)
{
// handle or raise exception
}
}
[/code]

un-register events
[code]
public static void removeEventReceivers(SPList docLib, SPEventReceiverType eventType, string assemblyName, string className)
{
try
{
int i;
for (i = 0; i < docLib.EventReceivers.Count; i++)
{
if (docLib.EventReceivers[i].Assembly.Equals(assemblyName)
&& docLib.EventReceivers[i].Class.Equals(className)
&& docLib.EventReceivers[i].Type.Equals(eventType))
{
docLib.EventReceivers[i].Delete();
}
} // looping thru event receivers.
docLib.Update();
}
catch(Exception ex)
{
// handle or raise exception
}
}
[/code]

Here is a list of events on which you can hook your custom code into:

Microsoft.SharePoint.SPWebEventReceiver : "Site Level"

SiteDeleted

Occurs after a site collection has been deleted.

SiteDeleting

Occurs when a site collection is being deleted.

WebDeleted

Asynchronous Afterevent that occurs after an existing Web site is completely deleted.

WebDeleting

Synchronous before event that occurs before an existing Web site is completely deleted.

WebMoved

Asynchronous after event that occurs after an existing Web site has been moved.

WebMoving

Synchronous before event that occurs before an existing Web site has been renamed or moved to a different parent object.

· Microsoft.SharePoint.SPListEventReceiver : "List Level"

FieldAdded

Occurs after a field link is added.

FieldAdding

Occurs when a field link is being added to a content type.

FieldDeleted

Occurs after a field has been removed from the list.

FieldDeleting

Occurs when a field is in the process of being removed from the list.

FieldUpdated

Occurs after a field link has been updated

FieldUpdating

Occurs when a field link is being updated

· Microsoft.SharePoint.SPItemEventReceiver : "List Item Level"

ItemAdded

Asynchronous After event that occurs after a new item has been added to its containing object.

ItemAdding

Synchronous before event that occurs when a new item is added to its containing object.

ItemAttachmentAdded

Asynchronous after event that occurs after a user adds an attachment to an item.

ItemAttachmentAdding

Synchronous before event that occurs when a user adds an attachment to an item.

ItemAttachmentDeleted

Asynchronous after event that occurs when after a user removes an attachment from an item.

ItemAttachmentDeleting

Synchronous before event that occurs when a user removes an attachment from an item.

ItemCheckedIn

Asynchronous after event that occurs after an item is checked in.

ItemCheckedOut

Asynchronous after event that occurs after an item is checked out.

ItemCheckingIn

Synchronous before event that occurs as a file is being checked in.

ItemCheckingOut

Synchronous before event that occurs after an item is checked out.

ItemDeleted

Asynchronous after event that occurs after an existing item is completely deleted.

ItemDeleting

Synchronous before event that occurs before an existing item is completely deleted.

ItemFileConverted


ItemFileMoved

Occurs after a file is moved.

ItemFileMoving

Occurs when a file is being moved.

ItemUncheckedOut

Synchronous before event that occurs when an item is being unchecked out.

ItemUncheckingOut

Synchronous before event that occurs when an item is being unchecked out.

ItemUpdated

Asynchronous after event that occurs after an existing item is changed, for example, when the user changes data in one or more fields.

ItemUpdating

Synchronous before event that occurs when an existing item is changed, for example, when the user changes data in one or more fields.



Cheers,
Sandeep