Creating a custom XPath function for the XSLT mapper in the SOA Suite

Sometimes the default XSLT-mapper in the SOA Suite just is not enough. You want a little bit more or you want something that is re-usable for other components. The answer lies in writing your own XPath function.

The first thing we need is to create a jar file which contains our functionality. Say we want a function which creates a displayname based on a few parameters. We will use Maven to create our jar. Start of with your basic maven structure and your default pom file.

Project
-src
   -main
      -java
      -resources
   -test
      -java
      -resources
-pom.xml

Your pom.xml wil be as basic as can be

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>nl.redrock</groupId>
	<artifactId>CustomXPath</artifactId>
	<version>1.0</version>
	<name>CustomXPath</name>
	<description>This jar contains classes which can be used for custom xpath</description>

	<dependencies>
 		<!-- Test dependencies -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		<dependency>
	<dependencies>
</project>

As you can see, we will use junit test to test my classes. Now lets build our functionality. Create a class NameCompiler in src/main/java

package nl.redrock.utils;


/**
 * XSLT Specific Mapper function.
 * 
 * Function is registered in a file with the naming convention
 * ext-mapper-xpath-functions-config.xml
 */
public class NameCompiler {

	/**
	 * This function is used to determine the lastname of a person based on its
	 * preference and partner details
	 * 
	 * @param aNameCode
	 *            the code (1=own, 2=partner, 3 partner-own,
	 *            4=own-partner)
	 * @param aPrefix
	 *            the person prefix
	 * @param aLastname
	 *            the lastname
	 * @param aPartnerPrefix
	 *            the partner prefix
	 * @param aPartnerLastname
	 *            the partner lastname
	 * @return the lastname based on the namecode
	 */
	public static String compileLastname(int aNameCode, String aPrefix,
			String aLastname, String aPartnerPrefix, String aPartnerLastname) {
		String result = null;
		switch (aNameCode) {
		/** Voorkeurnaamcode is eigen */
		case 1:
			result = aLastname;
			break;
		/** Voorkeurnaamcode is partner */
		case 2:
			result = aPartnerLastname;
			break;
		/** Voorkeurnaamcode is partner */
		case 3:
			if (aPrefix != null && aPrefix.length() > 0) {
				result = aPartnerLastname + " - " + aPrefix + " " + aLastname;
			} else {
				result = aPartnerLastname + " - " + aLastname;
			}
			break;
		/** Voorkeurnaamcode is partner */
		case 4:
			if (aPartnerPrefix != null && aPartnerPrefix.length() > 0) {
				result = aLastname + " - " + aPartnerPrefix + " "
						+ aPartnerLastname;
			} else {
				result = aLastname + " - " + aPartnerLastname;
			}
			break;
		default:
			result = "Onbekende naamvoorkeurscode!";
			break;
		}
		return result;
	}
}

Important here is that:

  • The method is public and static

Before you wrote this class, you will off course have written the junit tests as a good Test Driven programmer does 😉

The next thing we need to do is to add ad file which maps the XPath to this class. This file is named ext-mapper-xpath-functions-config.xml and is located in the src/main/resource/META-INF folder and looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<soa-xpath-functions xmlns="http://xmlns.oracle.com/soa/config/xpath" xmlns:roc="http://www.oracle.com/XSL/Transform/java/nl.redrock.utils.NameCompiler">
	<function name="roc:compileLastname">
		<className>nl.redrock.utils.NameCompiler</className>
		<return type="string"/>
		<params>
			<param name="naamcode" type="number"/>
			<param name="voorvoegsel" type="string"/>
			<param name="achternaam" type="string"/>
			<param name="partnervoorvoegsel" type="string"/>
			<param name="partnerachternaam" type="string"/>
		</params>
		<desc/>
		<detail>
			<![CDATA[Deze functie stelt de officiele achternaam samen obv voorkeursnaamcode.]]>
		</detail>
	</function>
</soa-xpath-functions>

Important here is that:

  • The namespace starts with ‘http://www.oracle.com/XSL/Transform/java/’ followed by the package name

This is basically it. Run mvn clean package to build the final .jar file. Check if the class is packaged and that the ext-mapper-xpath-functions-config.xml is located in the META-INF directory.

The only thing left to do is to add the jar to JDeveloper so we can make use if it. This can be done by opening Tools->Preferences and going to the SOA tab

and adding the just created jar file. You will need to restart you JDeveloper for the changes to take effect. When you have restarted, you will see the custom XPath under Component Palette->User Defined

In the XSLT files this will look like this:

<gen:Achternaam>
    <xsl:value-of select="roc:compileLastname($naamcode,$voorvoegsel,$achternaam,$partnervoorvoegsel,$partnerachternaam)"/>
</gen:Achternaam>

Don’t forget to add the namespace which should match the one you have defined in the ext-mapper-xpath-functions-config.xml.

Now that this is done, how do we make it work on the server? The only thing you have to do is to copy the jar file to /Oracle_SOA1/soa/modules/oracle.soa.ext_11.1.1/ folder and run the ant script. This will rebuild the registry classpath entries. After this, you will need to restart the server.

When the server is restarted check to see if it works……

For a good reference document see here

One Reply to “Creating a custom XPath function for the XSLT mapper in the SOA Suite”

  1. Pingback: Custom 11G XPath function not showing up in JDeveloper 12C

Leave a Reply

Your email address will not be published. Required fields are marked *

*