Creating extension functions |

This chapter describes how to create your own library of XPath extension functions which can be called within your XSLT transformations.

## Creating your extension functions

The first step is to write the Eiffel code for your extension functions. You do this by writing at least one Eiffel class. Usually you should create a separate class for each function, but if several functions are variations on a theme, it might be simpler for them all to share one class, and just use a different creation procedure for each implemented function. An example of this approach is the implementation of the core XPath functions fn:encode-for-uri(), fn:iri-to-uri() and fn:escape-html-uri(), which all share the same implementation code in XM_XPATH_ESCAPE_URI, the only difference between them being the set of reserved characters.

Your Eiffel class should be a descendant of `XM_XPATH_SYSTEM_FUNCTION` (if it is possible for your function to always be evaluated when the transformation is compiled, then it is more efficient to inherit fron `XM_XPATH_COMPILE_TIME_FUNCTION` instead).

Writing extension functions as descendants of `XM_XPATH_SYSTEM_FUNCTION` probably requires some understanding of how the XPath library works. This is not properly documented yet. If in doubt ask for help on one of the Gobo mailing lists.

You will usually want to redefine either `evaluate_item` or `create_iterator`, or both (if your function ever returns sequences of more than one item, then you will need to redefine `create_iterator`).

You may also need to redefine other routines. These routines are likely candidates:

`pre_evaluate`
  By default, the library will attempt to pre-evaluate your function at compile time, if it can determine that all the arguments are fixed values. If for some reason that is unsuitable behaviour, then you should redefine this routine to do nothing.
`simplify`
  This performs optimizations that do not depend upon the XPath static context. By default it just simplifies all the other arguments. This is a suitable point for setting optimization flags that depend upon the number of arguments actually passed.
`check_arguments`
  This routine checks the number and type of arguments. This is a suitable place for performing additional checks or optimizations on particular arguments.
`calculate_effective_boolean_value`
  This routine evaluates the function as a boolean.
`check_static_type`
  This routine performs static type checking on the function.
`optimize`
  This routine performs optimizations at compile time. By default it optimizes all the arguments.
`evaluate_as_string`
  This routine evaluates the function when it is known to return a single string.
`compute_special_properties`
  This routine sets flags for the optimization process.
`compute_intrinsic_dependencies`
  This routine sets flags for the optimization process.

You will also need to implement the following routines:

`item_type`
  This routine tells the static type checker and optimizer what type of items might be returned by the function. Be as specific as you can, so that more optimizations can be performed.
`required_type`
  This routine tells the static type checker what type and length of sequence is allowed for each argument.
`compute_cardinality`
  This routine tells the static type checker and optimizer now many items might be returned by the function.

You must also implement a creation routine with zero arguments. This must perform the following operations:

- Set the attributes `name` and `namespace_uri` to name your function.
- Set `fingerprint` to match `name` and `namespace_uri`.
- Set the attributes `minimum_argument_count` and `maximum_argument_count` to specify the number of permitted arguments.
- Finally create `arguments` and set `initialized` to `True`.

## Creating an extension function library

Next you should create a descendant of `XM_XPATH_FUNCTION_LIBRARY`. You need to implement two routines:

`is_function_available`
  If `a_fingerprint` is equal to the value of `fingerprint` for your function, then you should return `True` if `an_arity` is -1, or if it lies (inclusively) between the values that you set for `minimum_argument_count` and `maximum_argument_count` for your function.
`bind_function`
  You should create the function that matches `a_fingerprint`. Then call `set_arguments``(``some_arguments``)`. Then you should set `last_bound_function` to the created function.

  If the argument `is_restricted` is `True`, then your function is being bound within an [xsl:]use-when context. If it is sensible for your function to be callable in such a context, then by all means ignore this argument. Otherwise you should create an instance of `XM_XSLT_DEFERRED_ERROR`. See `XM_XSLT_BUILTIN_EXTENSION_FUNCTIONS` for an example.

## Informing the XSLT library of your extension function library

There is one last step to take, you have to tell the library about the existence of your function library.

Just pass your library as the sole argument to `add_extension_function_library` of `XM_XSLT_CONFIGURATION`. After this call, your library will be searched whenever a transformation is compiled.