Search This Blog

Wednesday, July 6, 2011

Examples of Velocity, xslt and StringTemplate


These template engines provide similar functionalities - transforming data into new contents based on a set of templates, and they are all compatible to java. You can pick any one of them as long as it can solve your problem. To process xml/html documents I would recommend xslt. Other text processing, I would recommend velocity. StringTemplate is powerful, but it is not well documented. If the task requires fast transformation and small memory use, dom parser based xslt transformation is not recommended. I will make a few simple examples in the article to bring you an idea of how they work.
 
Velocity,
First download velocity binary from http://velocity.apache.org/download.cgi.
Now I start eclipse and create a new project called VelocitySample, add 2 velocity jar files to build path.
 
package xish.velocity.app;

import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

public class VelocityDemo {

           public static void main(String[] args) {
                      Velocity.init();
                      Template tp = Velocity.getTemplate("./template/v1.vm");
                      VelocityContext ctx = new VelocityContext();
                      Collection users = new ArrayList();
                      users.add(new User("Jemmy", "jmy32@gmail.com"));
                      users.add(new User("Funy", "fol@abcenglish.com"));
                      users.add(new User("lao", "derr@yahoo.com"));
                      ctx.put("users", users);
                      Writer writer = new StringWriter();
                      tp.merge(ctx, writer);
                      System.out.println(writer);
           }

}
VelocityDemo.java
#foreach($user in $users)
$user.Name    $user.Email
#end
#include("./template/v2.vm")
v1.vm
The End!
v2.vm
Run VelocityDemo, it will generate following output:
Jemmy    jmy32@gmail.com
Funy    fol@abcenglish.com
lao    derr@yahoo.com
The End!

Xslt,

I create a new project in eclipse called XsltSample.
 
package xish.xslt.app;

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

public class XsltDemo {

           public static void main(String[] args) {
                      String xmlFile = "./data/users.xml";
                      String xsltFile = "./template/v1.xslt";

                      try {
                                 javax.xml.transform.Source xmlSource = new javax.xml.transform.stream.StreamSource(
                                                      xmlFile);
                                 javax.xml.transform.Source xsltSource = new javax.xml.transform.stream.StreamSource(
                                                      xsltFile);
                                 javax.xml.transform.Result result = new javax.xml.transform.stream.StreamResult(
                                                      System.out);

                                 javax.xml.transform.TransformerFactory transFact = javax.xml.transform.TransformerFactory
                                                      .newInstance();

                                 javax.xml.transform.Transformer trans = transFact
                                                      .newTransformer(xsltSource);

                                 trans.transform(xmlSource, result);
                      } catch (TransformerConfigurationException e) {
                                 e.printStackTrace();
                      } catch (TransformerFactoryConfigurationError e) {
                                 e.printStackTrace();
                      } catch (TransformerException e) {
                                 e.printStackTrace();
                      }
           }
}
XsltDemo.java
<?xml version="1.0" encoding="UTF-8"?>
<users>
           <user>
                      <name>Jemmy</name>
                      <email>jmy32@gmail.com</email>
           </user>
           <user>
                      <name>Funy</name>
                      <email>fol@abcenglish.com</email>
           </user>
           <user>
                      <name>lao</name>
                      <email>derr@yahoo.com</email>
           </user>
</users>
Users.xml
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
           version="1.0">
           <xsl:output method="text" indent="yes" />

           <xsl:import href="v2.xslt" />

           <xsl:template match="/">
                      <xsl:apply-templates select="users" />
                      <xsl:call-template name="end"/>
           </xsl:template>

           <xsl:template match="users">
                      <xsl:apply-templates select="user" />
           </xsl:template>
          
           <xsl:template match="user">
                      <xsl:value-of select="name" />
                      <xsl:text>    </xsl:text>
                      <xsl:value-of select="email" />
                      <xsl:text>&#xa;</xsl:text>
           </xsl:template>

</xsl:stylesheet>
v1.xslt
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
           version="1.0">
           <xsl:output method="text" indent="yes" />
          
           <xsl:template name="end">
                      <xsl:text>The End!</xsl:text>
           </xsl:template>
</xsl:stylesheet>
v2.xslt
Run XsltDemo, it will generate following output:
Jemmy    jmy32@gmail.com
Funy    fol@abcenglish.com
lao    derr@yahoo.com
The End!

StringTemplate,

Download StringTemplate from http://www.stringtemplate.org/download.html. Notice there are a few class name changes in comparison between v3 to v4. I downloaded the latest version v4.03 upon writing this post.
I created a new project in eclipse called StringTemplateSample, and add antlr-3.3-complete.jar and ST-4.0.3.jar to the build path.
 
package xish.stringtemplate.app;

import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupDir;

public class StringTemplateDemo {

          
           public static void main(String[] args) {

                      STGroup group = new STGroupDir("./template");
                      ST st = group.getInstanceOf("v1");

        st.addAggr("users.{ name, email }", "Jemmy", "jmy32@gmail.com");
        st.addAggr("users.{ name, email }", "Funy", "fol@abcenglish.com");
        st.addAggr("users.{ name, email }", "lao", "derr@yahoo.com");
       
        System.out.println(st.render());
        //v1(users) ::= "<users:{it|<it.name>    <it.email>; wrap}><\n><v2()>;"
        //System.out.println(st.render(20));
           }
}
StringTemplateDemo.java
v1(users) ::= "<users:{it|<it.name>    <it.email><\n>}><v2()>;"
v1.st
v2() ::= "The End!"
v2.st
Run StringTemplateDemo, it will generate following output:
Jemmy    jmy32@gmail.com
Funy    fol@abcenglish.com
lao    derr@yahoo.com
The End!

1 comment:

  1. I do get the impression that XSLT uses a in-memory presentation of XML, possibly DOM. How else could you navigate along the axes, like ancestor and aibling.

    Just try to transform a large XML document and you can expect memory problems. So I'm not sure if your statement is legitimate. FreeMarker e.g. has the option to use a DOM node as a model and I expect that using FreeMarker will perform similar to XSLT (or perhaps even better). So the real question is do you want a procedural template (FreeMarker) or a functional one (XSLT).

    I have done a lot of XSLT and the downside of XSLT is its maintenance, certainly if these stylesheets become more complex. You have to take the priority into account (and XSLT has no specifity rules like CSS, so before you know it you have the same matching rules and now it depends on the implementation of XSLT what happens :-( ), otherwise you can expect strange results. I have seen this happening when maintaining existing stylesheets. You just can't move template sections around. The outcome might be quite different (when using JAXP's TrAX). This can become a real nightmare.

    So from a maintenance point of view I'm not so sure if I would choose for XSLT especially when you are dealing with lot of stylesheets that are included and/or imported.

    ReplyDelete