Re: A WM brain bender: The solution
"marcel.huijkman" <[email protected]>
| Newsgroups | gmane.comp.java.webmacro.user |
|---|---|
| Message-ID | <[email protected]> |
Please don't do this via the #include directive. It's not an include and it sounds like a workaround for a specific problem! Don't misuse directive for other tasks as for where they were made for. A ex-collegue of mine made this allready and handed me the code, to see if it is good enough for the community (nice he), and I'm sure he won't mind that I put het source with this email. (and a template too!) The trick that you want: get a string from somewhere and use is as a kind of stamp and it works like this: #evalStringTemplate $myEvalVar to $myOutput myOutput :<BR>$myOutput The $myEvalVar in this example can be filled with: webmacro stuff (and yes, that's cool!) The string stays intact and the parsed string $myOutput has the result after evaluation of the $myEvalVar. Simple, efficient and just what you need. Please take a good look at it, and if it's suitable, give Mike Weerdenburg all the credits.
EvalStringTemplateDirective.java
(text/plain, 6.6 KB)
/*
* Copyright (C) 2005. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted under the terms of either of the following
* Open Source licenses:
*
* The GNU General Public License, version 2, or any later version, as
* published by the Free Software Foundation
* (http://www.fsf.org/copyleft/gpl.html);
*
* This software is provided "as is", with NO WARRANTY, not even the
* implied warranties of fitness to purpose, or merchantability. You
* assume all risks and liabilities associated with its use.
*
* See www.webmacro.org for more information on the WebMacro project.
*
* @author Mike Weerdenburg
*
* @version 14-01-2005
*
*/
package org.webmacro.directive;
import org.webmacro.*;
import org.webmacro.engine.*;
/**
* EvalStringTemplateDirective allows you to evaluate a string just like it is a include / template against the current context.<p>
*
* Syntax:<pre>
* #EvalStringTemplate $valueToEvaluateAsString [to $variable]
*</pre>
*
*/
public class EvalStringTemplateDirective extends Directive
{
/* the argument is NOT a file, but a string represending the template! */
private static final int PARSE_VALUE = 1;
private static final int PARSE_TO = 2;
private static final int PARSE_TO_VARIABLE = 3;
private Variable _varTarget = null;
private static final UndefinedMacro UNDEF = UndefinedMacro.getInstance();
private static final ArgDescriptor[] _args = new ArgDescriptor[]
{
new StringArg(PARSE_VALUE),
new OptionalGroup(2),
new KeywordArg(PARSE_TO, "to"),
new LValueArg(PARSE_TO_VARIABLE),
};
private static final DirectiveDescriptor _desc = new DirectiveDescriptor("evalStringTemplate", null, _args, null);
public static DirectiveDescriptor getDescriptor ()
{
return _desc;
}
//
// these values are customized for this directive during build()
//
/** Logging can be good */
protected Log _log;
/** the value as a Macro, if the value arg is a Macro */
protected Macro _macroValue;
/**
* the name given to the directive by webmacro configuration.
*/
protected String _directiveName;
public final Object build (DirectiveBuilder builder, BuildContext bc) throws BuildException
{
// Get a log-instance.
// In webmacro.properties : LogLevel.directive=DEBUG
_log = bc.getLog("directive");
// name of this directive
_directiveName = builder.getName();
// if a target provided, then output to the target!
if (builder.getArg(PARSE_TO_VARIABLE, bc) != null)
{
try
{
_varTarget = (Variable) builder.getArg(PARSE_TO_VARIABLE, bc);
}
catch (ClassCastException e)
{
// throw new NotVariableBuildException(myDescr.name, e);
}
}
Object o = builder.getArg(PARSE_VALUE, bc);
if (o instanceof Macro)
{
// The value passed to us was a Macro (needs to be evaluated later).
// If u use : #evalStringTemplate $myDatabaseFilledStringToEvaluate
_macroValue = (Macro) o;
}
else
{
// If it's not a Macro, then generate an BuildException.
// If u use : #evalStringTemplate "This is a string with nothing to parse!"
throw new BuildException("#" + _directiveName + " was expecting a non-static value to evaluate, example: #" + _directiveName + " \"$myDatabaseFilledStringToEvaluate is very interesting!\"");
}
return this;
}
/**
* Write out the included file to the specified FastWriter. If the
* included file is actually a template, it is evaluated against the
* <code>context</code> parameter before being written to the FastWriter
*/
public void write (FastWriter out, Context context) throws PropertyException
{
Broker broker = context.getBroker();
String strValue = null;
// the value arg passed to us was a Macro, so evaluate and check it now.
if (_macroValue != null)
{
Object obValue = _macroValue.evaluate(context);
// Only set the value if the macro provided not is null and not Undefined.
if ( (obValue != null) && (obValue != UNDEF) )
{
strValue = obValue.toString();
}
}
if (strValue == null)
{
throw new PropertyException("#" + _directiveName + " value cannot be undefined or null");
}
// Use the current templateName as templateName for the StringTemplate.
// exampl. c:/wwwroot/templates/test.wm
String templateName = context.getTemplateEvaluationContext()._templateName;
// Use the current template location & directive name, so whe can re-trace error's.
// exampl. c:/wwwroot/templates/test.wm:46.2 #evalStringTemplate
if (templateName.indexOf(" #" + _directiveName) == -1) templateName = context.getCurrentLocation() + " #" + _directiveName;
if (_log.loggingDebug())
{
_log.debug("#" + _directiveName + " \"valueToEvaluateAsStringTemplate\""
+ ((_varTarget == null) ? ""
: " to $" + _varTarget.getVariableName()));
}
if (_log.loggingWarning())
{
if (strValue.indexOf("#" + _directiveName) > -1)
{
// when in debug or warning mode, output a warning if a evalStringTemplate tries to use a evalStringTemplate
// there could be situtations where this is desired, but it's good to make
// the user aware of what they're doing
_log.warning("#" + _directiveName + " uses a #" + _directiveName + ", maybe itself? (endless loop!) at " + context.getCurrentLocation());
}
}
// Create the new StringTemplate.
Template tmplTemplate = new StringTemplate (broker, strValue, templateName);
if (_varTarget != null)
{
// if a target variable provided, then output to the target.
_varTarget.setValue(context, tmplTemplate.evaluateAsString(context));
}
else
{
// else output to the specified FastWriter.
out.write(tmplTemplate.evaluateAsBytes(out.getEncoding(), context));
}
}
public void accept (TemplateVisitor v)
{
v.beginDirective(_desc.name);
v.visitDirectiveArg("EvalStringTemplate", _macroValue);
if (_varTarget != null) v.visitDirectiveArg("EvalStringTemplateTarget", _varTarget);
v.endDirective();
}
}
EvalStringTemplateDirective.wmt
(text/plain, 667 B)
#set $Response.ContentType = "text/html; charset=$CharSet"
$HTMLCopyright
<META HTTP-EQUIV="expires" CONTENT="NOW">
<html>
<head>
<title></title>
</head>
<BODY>
#set $myVar1 = "number 1"
#set $myVar2 = "number 2"
#setblock $myEvalVar #begin
#text #begin
#foreach $item in ["aap (monkey)","noot (nut)","mies (girls name)"]
{
item : $item<BR>
}
myVar1 : $myVar1<BR>
myVar2 : $myVar2<BR>
#end
#end
<HR><PRE>$myEvalVar</PRE><HR>
#evalStringTemplate $myEvalVar
<BR><HR><BR>
## Output to a variable...
#evalStringTemplate $myEvalVar to $myOutput
\myOutput :<BR>$myOutput
#include as template "$(EngineTemplateDir)_includes/footer.inc"
</BODY>
</HTML>