XSL Extension Objects

Author:JonK
Last Updated:May 10, 2017 12:18 PM

Introduction

This is a breif note about how to integrate C# method calls into XSL code. Extension Objects are a tool that .NET provides a way to integrate managed code as a way to perform tasks that XSL just can't do. 

This is not about xsl:script. DO NOT EVER use xsl:script. 

Example

This example is from Base Titan code. In the Content Import utility, I present to the user a grid showing the content of the data file they uploaded. In cases where a data column contains XML content, I want write that out as a string. However, XSL doesn't allow you to easily write the "inner XML" out as a string, so I'm using a simple extension object to do this.

Extension Object

When you pass an object into XSL, you are passing an instance of a plain ole object so you can call its methods. For my use it was a for simple function calls, so I had started with a static object. You can't do that though. It wants an instance of an object. 

So base has an object called ContentImportExtensions.

public class ContentImportExtensions
{
	public ContentImportExtensions() { }

	public string GetInnerXml(XPathNodeIterator node)
	{
		node.MoveNext();
		return (node.Current.HasChildren) ? node.Current.InnerXml : node.Current.Value;
	}
}

It has one method, GetInnerXml that takes a XPathNodeIterator as its parameter. This is necessary because I'm processing the an XML element from an XSL nodeset.

The way you pass the object reference into an XSL is through the XsltArgumentList.

XsltArgumentList argList = new XsltArgumentList();
argList.AddExtensionObject("urn:ImportExt", new ContentImportExtensions());

You provide a namespaceUri as the first parameter. This will be used in the XSL code to provide reference for the function call. The second parameter is the instance of the extension object.

XSL

At the top of your XSL in the xsl:stylesheet element, you define the namespace that refers to the extension object.

<xsl:stylesheet version="1.0" ... xmlns:ImportExt="urn:ImportExt" exclude-result-prefixes="msxsl ImportExt">

And in the XSL code when you need to call the method, you do so through an xsl:value-of 

<xsl:template match="*" mode="cell">
	<xsl:variable name="data">
		<xsl:choose>
			<xsl:when test="./*">
				<xsl:value-of select="ImportExt:GetInnerXml(.)"/>
			</xsl:when>
			<xsl:otherwise>
				<xsl:value-of select="."/>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:variable>
	<td>
		<div class="cell" title="{$data}">
			<xsl:value-of select="$data" disable-output-escaping="yes"/>
			<xsl:comment>ph</xsl:comment>
		</div>
	</td>
</xsl:template>

 

top