Commerce Server 2009 XSLT Web Parts
Many of the web parts that come as part of the SharePoint Commerce Services are based on XSLT transforms. This approach provides Commerce administrators the ability to change the rendering of a web part without the code change, recompile and re-deploy cycle. You can see what any given XSLT looks like by browsing to one of the pages within the SharePoint Commerce Services Default Site that utilizes an XSLT based web part. Take the Category page for example. By default this page, which uses the Category.aspx template, includes the Product Query Web Part. When placing the page and the web part into edit mode, the browser renders a drop list control titled “Template to Display”.
|
This control allows the administrator/editor to select an XSLT to apply the data returned from the Commerce Catalog. You can actually see the XSLT by clicking on the ellipses button “…” in the next control below titled “Template Details”.
|
Below the “Template Details” control is a third titled “Template Properties”. Clicking the “Select Properties…” button opens a popup window which allows one to select what product properties, including variant properties will rendered by the web part.
|
|
By changing the properties that are to appear, you are actually modifying the XSLT. You just click away and the underlying web part editor takes care of modifying the XSLT source. You can even save your modifications to another “template” so as to avoid modifying the out of the box “templates”. Note that I say “template” as opposed to saying ”XSLT”. I say “template” because what you are saving is not just an XSLT. A Commerce Server Web Part “template” has an XSLT within it that is used to transform XML into an HTML rendering, however there is more to a “template” than just the XSLT. If you navigate to the “Commerce Server Templates” list you can view the available templates, including any that you may have modified and saved to a different name.
|
|
|
When you click on one of these within this SharePoint list the browser will launch Notepad so that you can take a look at what is contained in these so called “templates”. I suggest that you open one up and take a look. You’ll notice (or at least I did), two interesting thing about this so called “template” document. The first is what while you can see the XSLT within the document, it is prefixed with some other XML content. In the DefaultSite_ProductQuery.template for example, you’ll see that the file begins with
<?xml version="1.0" encoding="utf-16"?>
<template>
<productProperties>
<property Name="DisplayName" />
<property Name="Id" />
<property Name="Image_filename" />
<property Name="ListPrice" />
<property Name="Description" />
</productProperties>
<variantProperties>
<property Name="DisplayName" />
<property Name="Id" />
<property Name="ListPrice" />
</variantProperties>
<productDefinition>
</productDefinition>
<xslTransform>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">These XML elements are used by the WebPart editor to keep track of what Product properties, Variant properties etc. are currently configured for rendering within the transform. Much of this is handled by the class XsltTemplateEditorPart class. The second thing I noticed is a non-standard element within the XSLT portion of the transform. This is the <<XsltAction> element.
<XsltAction Id="AddToCart"
Type="Microsoft.Commerce.Portal.UI.Catalog.WebControls.VariantAddToCartXsltAction, Microsoft.Commerce.Portal.UI.Catalog, Culture=Neutral, Version=1.0.0.0, PublicKeyToken=942403bb93c53277">
<ConfigSettings>
<ConfigSetting Name="ProductId">
<xsl:value-of select="property[@name='Id']" />
</ConfigSetting>
<ConfigSetting Name="DisplayAddToShopperList">true</ConfigSetting>
<ConfigSetting Name="AddToShopperListDefault">false</ConfigSetting>
<ConfigSetting Name="ImageButtonUrl"></ConfigSetting>
</ConfigSettings>
</XsltAction>If you dig through the source of the Commerce Server Extensibility kit you’ll learn that during rendering of the web part, in this case the Product Query Web Part, after the Commerce Server Catalog data is retreived, converted to XML and the XSLT portion of this “template” is applied, this <XsltAction> element is turned into something else. The RenderXsltActions method of the ProductQuery web part class performs this action. This method, with the help of the XsltActionHelper class, finds all occurrences of <XsltAction> nodes within the XSLT transform results. It uses the element and its attributes to instantiate the specified web control and then have the control instance render its contents to a StringBuilder. String class Replace method is then used to replace the <XsltAction> element within the XSLT transform results. The outText parameter is the result of the XSLT already applied to the XML. Below is the relevant code fragment:
protected string RenderXsltActions(string outText)
{
Collection<XsltAction> xsltActions = XsltActionHelper.GetXsltActions(outText);
int controlIndex = 0;
foreach (XsltAction action in xsltActions)
{
Type xsltActionType = Type.GetType(action.ClassType);
if (xsltActionType == null)
{
throw new XsltActionException("Cannot instantiate XSLT action " + action.Id);
}
XsltActionControl control = Activator.CreateInstance(xsltActionType) as XsltActionControl;
try
{
string controlUniqueId = this.UniqueID + "$" + action.Id + controlIndex.ToString(CultureInfo.InvariantCulture);
control.Initialize(controlUniqueId, this.GetProductContext(), action.ConfigSettings, this.Page.ClientScript.GetPostBackClientHyperlink(this, controlUniqueId));
StringBuilder sb = new StringBuilder();
control.RenderControl(new HtmlTextWriter(new System.IO.StringWriter(sb, CultureInfo.InvariantCulture)));
outText = outText.Replace(action.TagSnippet, sb.ToString());
controlIndex++;
}
catch (XsltActionException)
{
throw;
}
}
return outText;
}This resulting string is then used to actually render the web part within the RenderContents() method. While this seems complex and “round about”, it provides a level of flexibility that would not be possible otherwise.