I have simple set of velocity templates. When I am trying to merge using NVelocity, the macros from other templates are not executing. The template contents are as follows:
V1.vm
#parse("V2.vm")
#foreach( $customer in $customers)
Hello $customer.Name!
#set($a =$customer.getage())
#age($a)
#end
V2.vm
#macro ( age $a )
#if($a<18)
Minor
#else
Major
#end
#end
On merge, the output is:
Hello User1!
#age(33)
Hello User2!
#age(13)
The macro doesn't work because NVelocity (and its ancestor Velocity) determine if #age
is a directive or macro at parse time, while the #age
macro gets discovered at runtime as it jumps into the other template, and so it is passed through as text.
To get around this you need to make the macro available to the parser before it parses your V1.vm
's #foreach
. You can obviously do this by putting the macro inline in that file, but I assume you intend to reuse it in other templates which is why you've got it separate now.
The other option is to put the macro in the macro library, either the one NVelocity will automatically load (VM_global_library.vm
) or a custom one. If you create a template named VM_global_library.vm
at the root of your templates directory NVelocity will automatically load this first before parsing anything, otherwise create your own macro template file and register it with the VelocityEngine
with the velocimacro.library
property. See the Velocity documentation for a more detailed explanation of the properties.
I've included a working example of using a custom macro library:
class Customer
{
public string Name { get; set; }
public int Age { get; set; }
public int GetAge() { return Age; }
}
class Program
{
static void Main(string[] args)
{
VelocityEngine velocityEngine = new VelocityEngine();
ExtendedProperties extendedProperties = new ExtendedProperties();
extendedProperties.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, "Templates");
extendedProperties.SetProperty(RuntimeConstants.VM_LIBRARY, "MyMacros.vm");
velocityEngine.Init(extendedProperties);
VelocityContext context = new VelocityContext();
context.Put("customers", new Customer[] {
new Customer { Name = "Jack", Age = 33 },
new Customer { Name = "Jill", Age = 13 }
});
using (StringWriter sw = new StringWriter())
{
bool result = velocityEngine.MergeTemplate("V1.vm", context, sw);
Console.WriteLine(sw.ToString());
}
}
}