Tuesday, August 21, 2012

NVelocity Template Engine

Note: The NVelocity project was abandoned in 2009, I've wanted to write this article back in November 2010, but I've found a few minutes only recently and in the hope its not a complete waste of time, here you have it with a some modifications and updates.

Velocity was one of the more advanced string templating engines around that time, it didn't take long to port it to .NET which became NVelocity. if you're porting an old application and need a transition time that all your templates will work before you can convert them to one of the more recent and advanced templating engines such as Razor, you may have found the demo program you needed.

I've tried both Castle NVelocity and Terri Liang's NVelocity port, I'm not sure which came before which, if one is an improvement of the other, but I needed something that supports recursive macros and string templates (instead of file/resource templates) which Castle didn't, so I've used the one from Terri Liang, which did.

Apache's velocity has the documentation for the syntax.

First instantiate a new engine:

NVelocity.App.VelocityEngine engine = new NVelocity.App.VelocityEngine();

//set log class type
engine.SetProperty(NVelocity.Runtime.RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, typeof(TemplateEngineLog));

//switch to local context, this way each macro/recursive execution uses its own variables.
engine.SetProperty(NVelocity.Runtime.RuntimeConstants.VM_CONTEXT_LOCALSCOPE, "true");

//allows #set to accept null values in the right hand side.
engine.SetProperty(NVelocity.Runtime.RuntimeConstants.SET_NULL_ALLOWED, "true");

//set template resource loader to strings
engine.SetProperty("resource.loader", "string");
engine.SetProperty("string.resource.loader.class", "NVelocity.Runtime.Resource.Loader.StringResourceLoader");

//initialize engine.

Then assign a new logger if error reporting is desired:

TemplateEngineLog log = new TemplateEngineLog();
engine.SetProperty(NVelocity.Runtime.RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, log);

Then create a context, its similar to ViewData:

//create a context
NVelocity.VelocityContext vcontext = new NVelocity.VelocityContext();

//put default values
vcontext.Put("null", null);
vcontext.Put("true", true);

//add the context values
foreach (var key in context.Keys)
    vcontext.Put(key, context[key]);

Then we have two options, either a one time execution of a template with this:

engine.Evaluate(vcontext, sw, "", template)

or multiple executions - meaning, the template will be compiled  so it will execute a lot faster:

//gets the string resource repository
var repo = NVelocity.Runtime.Resource.Loader.StringResourceLoader.GetRepository();
Guid guidcode = Guid.NewGuid();

//puts a new template inside it
repo.PutStringResource(guidcode.ToString(), template);

nvtemplate = engine.GetTemplate(guidcode.ToString(), "UTF-8");

and for the execution:

//merge uses a saved template
nvtemplate.Merge(vcontext, sw);

The demo project is located at:

No comments:

Post a Comment