There are a couple of issues, which are obscured by the fact that the samples in the WmXSLT package work.
To help explain, we’ll look at two lines from the dateInt.xsl sample found in pub/samples/xdocs within the WmXSLT package.
xmlns:Output = “java://com.wm.pkg.xslt.extension.Output”
The line above declares a namespace and identifies the fully-qualified name of the Java class to use. Alas, in this case, this class does not exist. The sample still works, however, because the classname is never referenced within the XSL to create a new “Output” object. This leads us to the second line of interest.
xsl:value-of select=“Output:put($output, ‘year’, $year)”
This indicates to invoke the ‘put’ method on the $output object instance. The sample doesn’t create an instance of the Output class to assign to $output so how does this work?
It works because transformSerialXML creates an instance of com.wm.pkg.xslt.extension.OutputMap and sets the “output” parameter (declared in the XSL but never initialized) by calling transformer.setParameter.
The $output object is thus initialized with an OutputMap object. This class, which extends java.util.HashMap, has a put method. The XSL processor can successfully invoke the method (via reflection).
Lastly, after the transform method is called, transformSerialXML iterates over the output object that it passed to the transform and puts each output key/value pair into the pipeline under the xslParamOutput document.
Below is the Java code modified to create and process the output parameter.
[highlight=java]
IDataHashCursor idc = pipeline.getHashCursor();
idc.first( “stylesheetSystemId” );
String stylesheetSystemId = (String)idc.getValue();
idc.first( “document” );
String document = (String)idc.getValue();
idc.first( “encoding” );
String encoding = (String)idc.getValue();
idc.first( “xslParamInput” );
IData xslParamInput = (IData)idc.getValue();
IDataHashCursor idcParamInput = null;
if(xslParamInput != null)
{
idcParamInput = xslParamInput.getHashCursor();
}
try{
//transform input string into bytes and then into InputStream and then into Source
byte documentBytes = document.getBytes(encoding);
java.io.ByteArrayInputStream documentInputStream = new java.io.ByteArrayInputStream(documentBytes);
javax.xml.transform.stream.StreamSource documentSource = new javax.xml.transform.stream.StreamSource(documentInputStream);
//create the object that will hold the output
java.io.CharArrayWriter transformedDocWriter = new java.io.CharArrayWriter();
javax.xml.transform.stream.StreamResult transformedDocResult = new javax.xml.transform.stream.StreamResult(transformedDocWriter);
//create the XSL factory
javax.xml.transform.TransformerFactory fabrique = javax.xml.transform.TransformerFactory.newInstance();
//create the XSL template file
java.io.File stylesheet = new java.io.File(stylesheetSystemId);
javax.xml.transform.stream.StreamSource stylesource = new javax.xml.transform.stream.StreamSource(stylesheet);
javax.xml.transform.Templates template = fabrique.newTemplates(stylesource);
//get the transformer for this template
javax.xml.transform.Transformer transformer = template.newTransformer();
transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, “yes”);
transformer.setOutputProperty(javax.xml.transform.OutputKeys.ENCODING, encoding);
//set input parameters (if applicable)
if(idcParamInput != null)
{
idcParamInput.first();
do
{
transformer.setParameter(idcParamInput.getKey(), idcParamInput.getValue());
}
while(idcParamInput.next());
//destory the cursor, now useless:
idcParamInput.destroy();
}
// The next 2 lines are new
java.util.HashMap output = new java.util.HashMap();
transformer.setParameter(“output”, output);
//transform
transformer.transform(documentSource, transformedDocResult);
// This output handling block is new
if(!output.isEmpty())
{
IData xslParamOutput = IDataFactory.create();
IDataCursor paramCursor = xslParamOutput.getCursor();
java.util.Iterator keys = output.keySet().iterator();
Object name = null;
Object value = null;
for(; keys.hasNext(); paramCursor.insertAfter((String)name, value))
{
name = keys.next();
value = output.get(name);
}
idc.insertAfter(“xslParamOutput”, xslParamOutput);
}
//access the result
String transformedDocument = ((java.io.CharArrayWriter)transformedDocResult.getWriter()).toString();
//set it in the pipeline
idc.first();
idc.insertAfter(“transformedDocument”, transformedDocument);
}
catch(Exception e){
idc.first();
idc.insertAfter(“output”, e.getMessage());
}
//destroy the pipeline cursor
idc.destroy();[/highlight]
Now that we’ve explored how to make it work, can I talk you out of doing this? 
Reimplementing transformSerialXML in your own Java service seems really unnecessary. It isn’t any more “lightweight”–it’s doing the same thing with the same XSLT engine within IS. Working with strings as input and output may be more convenient, but that can be achieved as described above with a simple FLOW wrapper.
Are there other goals you’re looking to achieve?
#Integration-Server-and-ESB#webMethods#Flow-and-Java-services