A generic way to use template variables in LiveCycle ES2

I saw a very interesting question on the Adobe Forums recently. Someone was asking if it was possible to use the setValue service to process a variable that was setup as a template. For those of you that are not familiar with templates in LiveCycle ES2, a template is basically a string value that has embedded xPath expressions. The idea is to have a chunk of text where some parts of it are substituted with runtime data values. Here is an example of a template:

Your name is {$/process_data/@FullName$} and your address is {$/process_data/@Address$}.

The end goal of course is for some processor to take the above template and replace the variable text {$ … $} with the actual value resolved from the xPath query.

The answer to the question of the setValue service being able to process such a template is unfortunately … no. The only way you could construct a dynamic string like this would be to use the concat() method in setValue. Sounds like a decent approach, but the problem is that if you want to change the text surrounding the dynamic values you have to touch your process map. Not so cool :)

My first reaction to this problem was to think of some way we could work around this limitation. What better way to implement a workaround then the executeScript service. With the executeScript service, you can write your own Java code while having access to the context of your LiveCycle ES2 process. For more information about the executeScript service, go to http://help.adobe.com/en_US/livecycle/9.0/workbenchHelp/help.htm?content=000581.html#2821118.

OK, now I am committed to writing some Java code. No big deal. the first step is to find some effective way to parse the template string and locate the variable text blocks identified by {$ and $}. Naively, I think regex. Ugh.. regex is like black magic to me. With some help from Danny Saikaly I get some funky regex statement that seems to work and I end up with code like this:

import java.util.regex.*;

Pattern variablePattern = Pattern.compile("\\{\\$([^\\$]*)\\$\\}");
String template = patExecContext.getProcessDataStringValue("/process_data/@templateString");
Matcher variableMatcher = variablePattern.matcher(template);
StringBuffer result = new StringBuffer();
while (variableMatcher.find())
{
    MatchResult _match = variableMatcher.toMatchResult();
    String xPathString = _match.group();
    xPathString = xPathString.substring(xPathString.indexOf("$") + 1, xPathString.lastIndexOf("$"));
    String value = patExecContext.getProcessDataStringValue(xPathString);           
    variableMatcher.appendReplacement(result, value);
}
variableMatcher.appendTail(result);
patExecContext.setProcessDataStringValue("/process_data/@resultString",result.toString();

NOTE: the double slashes “\\” in the regex are used to escape special characters here because of Java.

Then Danny makes a good observation, better test this thoroughly because you want to make sure that special characters in variable names are handled correctly, etc. Of course, he’s right. So now I am starting to think… “There has to be a better way to do this!!!”

I reached out to one of the LiveCycle ES engineers, Florantin Wandeler. I tell him about what I am trying to do and he also rains on the parade (rightfully so)… “That’s nice, but what if you have embedded xPath expressions?” … Hmmm, didn’t think of that! He then puts me onto a wicked useful, but not documented built-in function called replacePathExpressions(). Of course this makes sense, LiveCycle ES2 uses templates for many services, it’s just that it’s not exposed as a generic service. Quickly, I replace the code above with this:

//Get the templateString process variable value.
String template = patExecContext.getProcessDataStringValue("/process_data/@templateString");

// Call the replacePathExpressions() method.
// It is a built-in method that will look for all {$ $} variable text and process each xPath expression and replace them in the text.
String result = patExecContext.replacePathExpressions(template);

// Now, the result string contains all of the resolved xPath statements.
// Let's set the process variable that will hold the result.
patExecContext.setProcessDataStringValue("/process_data/@resultString",result);

HOW COOL IS THAT?!?!?

Comments Closed