How to extend the functionality of the .Net XSLT processor using your own objects.

Ibex supports the calling of methods on .Net objects from within XSL stylesheets. This feature allows you to programmatically extend the functionality of the .Net XSL processor.


A PDF file is created in Ibex by creating an FODocument object and calling the generate() method on that object. The call to generate can be passed an instance of a .Net object (in this example we use C# but any language will work), and within the XSL stylesheet you can call methods provided by that object.

Creating an object to invoke

The object to be invoked from XSL needs to be compiled and linked with the assembly which calls Ibex.

In this simple example we will use an object called Forecaster for generating random temperature forecasts. This object has a single method called Generate.

The code for this object is:

using System;
public class Forecaster {
  private Random _rand = new Random();
  public double Generate( int max ) {
    return Math.Round( _rand.NextDouble() * max, 2 );

Telling Ibex about the object

You pass Ibex the object you wish to call by passing it as a parameter to the generate() method. This method takes a System.Collections.Hashtable as the 5th parameter. This code shows how to create a Forecaster object and pass it to Ibex.

using System;
using System.IO;
using System.Xml.Xsl;
using System.Collections;

using ibex4;

public class Invoke {

  public static void Main( string[] args ) {

    if( args.Length < 3 ) {
        Console.WriteLine( "forecast xml-file xsl-file pdf-file" );

    FODocument doc = new FODocument();

    Hashtable xslt_args = new Hashtable();

    xslt_args[ "" ] = new Forecaster();

    Stream xml_stream = new FileStream( args[0], FileMode.Open, FileAccess.Read );
    Stream xsl_stream = new FileStream( args[1], FileMode.Open, FileAccess.Read );
    Stream pdf_stream = new FileStream( args[2], FileMode.Create, FileAccess.Write );

    Console.WriteLine( "forecast: {0} + {1} = {2}", args[0], args[1], args[2] );

    doc.generate( xml_stream, xsl_stream, pdf_stream, true, xslt_args );

This code is contained in the file forecast.cs.

The key part of the code is this:

Hashtable xslt_args = new Hashtable();

xslt_args[ "" ] = new Forecaster();

where we create an instance of the Forecaster object and add it to the collection of arguments for passing to Ibex.

The namespace URI used when adding the object to the collection can be any string, the important thing is that it matches the namespace URI used in the XSL stylesheet (see below).

Declaring the namespace in XSL

Before we can call the object in XSL we need to declare the namespace URI we will use when we call it. This must be identical to the namespace URI used when we added the object to the parameters collection as shown above.

The stylesheet used in this example is forecast.xsl, which looks like this:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"  xmlns:xsl=""

    <xsl:strip-space elements="*"/>

    <xsl:template match="forecast">


          <fo:simple-page-master master-name="page-layout">
            <fo:region-body margin="2.5cm" region-name="body"/>

        <fo:page-sequence master-reference="page-layout">
          <fo:flow flow-name="body">
            <xsl:apply-templates select="city"/>



    <xsl:template match="city">
        <xsl:value-of select="@name"/> <xsl:value-of select="forecaster:Generate( 30 )"/>

Calling the method in XSL

The call to the method on our object looks like this:

<xsl:value-of select="forecaster:Generate( 30 )"/>

The method takes one argument in the C# code, so we must pass one argument in the stylesheet.

Note that method names are case sensitive.

Whenever this xsl:template is executed, a call will be made to our .NET object and the result inserted into the results of the XSL transformation. The PDF file created by this example looks like this: forecast.pdf


Files used in this example are:


Copyright (c) 2002-2023 Visual Programming Limited