21 December 2009

How to call XSLT template from Your Code

How to call XSLT template from Your Code

In this post, I'll talk about calling XSLT template from Java code, However, you can apply this idea on your programming language.

Suppose you have an XSLT document that contains the following code:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<!--
Do logic here
-->
</xsl:template>

<xsl:template name="calculate">
<xsl:param name="param1" />
<xsl:param name="param2" />
<xsl:param name="type" />
<result>
<xsl:choose>
<xsl:when test="$type='add'">
<xsl:value-of select="$param1 + $param2" />
</xsl:when>
<xsl:when test="$type='sub'">
<xsl:value-of select="$param1 - $param2" />
</xsl:when>
<xsl:when test="$type='mult'">
<xsl:value-of select="$param1 * $param2" />
</xsl:when>
<xsl:when test="$type='div'">
<xsl:value-of select="$param1 div $param2" />
</xsl:when>
<xsl:otherwise>
<xsl:text>Invalid operand</xsl:text>
</xsl:otherwise>
</xsl:choose>
</result>
</xsl:template>
</xsl:stylesheet>

What if you need to call the template "calculate" From your Java code.
I've written a Java Class that facilitate calling calling XSLT templates, Here's the class signature (the source code attached):

public class XSLTemplate {
private String styleSheetPath;
private String templateName;
private Map<String, String> parameters;

public Node call() throws TransformerConfigurationException, TransformerException;
}

It contains 3 fields, styleSheetPath to set the physical location of your XSLT file that contains the template you need to call, templateName is the template name and parameters is a map that contains key:value pairs of the param name and value to pass to the template.

the method "call()", calls the template after setting its fields values, It returns an org.w3c.dom.Node Object that you will need to parse to get the desired output.

Example using XSLTemplate:

package org.daz.xslUtil;

import java.util.HashMap;
import java.util.Map;

import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;

import org.w3c.dom.Node;

public class Test {
public static void main(String[] args) throws TransformerConfigurationException, TransformerException {

XSLTemplate template = new XSLTemplate();
template.setStyleSheetPath(Test.class.getClassLoader()
.getResource("org/daz/xslUtil/converter.xsl")
.getPath());
template.setTemplateName("calculate");
Map<String, String> params = new HashMap<String, String>();
params.put("param1", "100");
params.put("param2", "250");
params.put("type", "add");
template.setParameters(params);
Node node = template.call();
if (node != null) {
System.out.println(node.getChildNodes().item(0).getTextContent());
}else {
System.out.println("Some error occured!");
}
}
}

Here's the complete code of the XSLTemplate class:

package org.daz.xslUtil;

import java.io.StringReader;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Node;

/**
* To Call XSLT template from Java Code
*
* @author mohammed hewedy <br />
* mhewedy@gmail.com
*/
public class XSLTemplate {

private String styleSheetPath;
private String templateName;
private Map<String, String> parameters;

private Logger logger = Logger.getLogger(XSLTemplate.class.getSimpleName());

public XSLTemplate() {
}

public XSLTemplate(String styleSheetPath, String templateName,
Map<String, String> parameters) {
this.styleSheetPath = styleSheetPath;
this.templateName = templateName;
this.parameters = parameters;
}
public XSLTemplate(String styleSheetPath, String templateName) {
super();
this.styleSheetPath = styleSheetPath;
this.templateName = templateName;
}

public String getStyleSheetPath() {
return styleSheetPath;
}
public void setStyleSheetPath(String styleSheetPath) {
this.styleSheetPath = styleSheetPath;
}
public String getTemplateName() {
return templateName;
}
public void setTemplateName(String templateName) {
this.templateName = templateName;
}
public Map<String, String> getParameters() {
return parameters;
}
public void setParameters(Map<String, String> parameters) {
this.parameters = parameters;
}

/**
* Call this method to execute the template
* @return Node object by the resulting document to parse and obtain the result,
* returns null in the following cases:
* <ul>
* <li>StyleSheetPath property is null<li>
* <li>TemplateName property is null<li>
* </ul>
* @throws TransformerConfigurationException
* @throws TransformerException
*/
public Node call() throws TransformerConfigurationException, TransformerException{
Transformer transformer = null;
Source xslSource = null;
Source dummyIn = null;
DOMResult result = null;

xslSource = constructStyleSheet();
if (xslSource== null)
return null;

transformer = TransformerFactory.newInstance().newTransformer(xslSource);
dummyIn = new StreamSource(new StringReader("<empty />"));
result = new DOMResult();
transformer.transform(dummyIn, result);

return result.getNode();
}

/**
* Returns Source of type StreamSource , or null if any of XSLTemplete.StyleSheetPath or
* XSLTemplete.TemplateName is null
* @return
*/
Source constructStyleSheet() {
if (!validate())
return null;

Source src = null;
StringBuffer sb = new StringBuffer();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
sb.append("<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">");
sb.append("<xsl:include href=\"" + getStyleSheetPath() + "\" /> ");
sb.append("<xsl:template match=\"/\">");
sb.append("<xsl:call-template name=\"" + getTemplateName()+ "\">");

Map<String, String> params = getParameters();
if ( params != null) {
Iterator<String> keyIter = params.keySet().iterator();
while (keyIter.hasNext()) {
String name = keyIter.next();
String value = params.get(name);
sb.append("<xsl:with-param name=\"" + name + "\" select=\"'" + value + "'\" />");
}
}
sb.append("</xsl:call-template>");
sb.append("</xsl:template>");
sb.append("</xsl:stylesheet>");
logger.log(Level.FINE, sb.toString());
src = new StreamSource(new StringReader(sb.toString()));
return src;
}

boolean validate() {
if (getStyleSheetPath()==null || getTemplateName()==null)
return false;
// TODO: validate TemplateName to make sure it is a valid XSLT identifier
return true;
}
}

2 comments:

Anonymous said...

Hi,
I try the source code and get this error message: Exception in thread "main" java.lang.NullPointerException


could you help?Thanks

mhewedy said...

It should work, please put the complete stack trace here.