3

我有一个插件项目,我正在使用 Velocity 模板。用户可以从首选项页面更改模板正文,我想在用户单击首选项页面中的“确定”时获取模板正文中的变量。我需要帮助才能从 Velocity 模板正文中提取变量。

4

4 回答 4

4

Velocity 使用 JavaCC 解析模板并创建 AST。

RuntimeInstance 是解析模板所需的全部内容。

RuntimeInstance ri = new RuntimeInstance();
SimpleNode node = ri.parse( reader, "templateName" );

现在您必须根据需要扩展 BaseVisitor。BaseVisitor 是所有访问者的抽象类。BaseVisitor 有一种节点类型的方法,因此您可以轻松过滤 AST 节点。

ParserVisitor visitor = new BaseVisitor() {
@Override
public Object visit(final ASTReference node, final Object data) {
    //insert here your logic ...
    System.out.println(node.getFirstToken();
    //use super.visit( node, data) if you need to traverse all node children 
    return null;
    }
};

然后访问节点...

visitor.visit(node, null);

如果您有如下模板:

some text $var other text

建议的代码只打印出来$var

请注意,ASTReference 是 ANY 引用。如果您有如下模板:

some text $var other text
#set( $primate = "monkey" )

这段代码打印出来:$var$primate

于 2014-03-29T14:34:51.617 回答
0

我能想到的唯一方法是在速度引擎中添加类似这样的内容:

VelocityContext context = new VelocityContext();
context.put("parameters", new HashMap());

...在模板中,让用户将值放入参数哈希图中,如下所示:

#set ($t = $parameters.put("value", "key"))

(重要:用户必须为临时参数赋值,例如 $t)

...然后,在渲染后,取出值:

HashMap map = (HashMap)context.get("parameters");
for (String key : map.keySet()) {
    // ...
}
于 2013-08-09T15:49:42.407 回答
0

我通过注册一个可记忆实例的事件然后使用盒式磁带中的事件评估模板来做到这一点。这不是 100% 的防弹,因为引用可以包含很多不同的东西,但我还没有看到一个明确的例子,它也失败了。

import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.event.EventCartridge;
import org.apache.velocity.app.event.ReferenceInsertionEventHandler;

import java.io.StringWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class TemplateAnalyzer{

public static Set<String> getReferences(String template){
    HashSet<String> names = new HashSet<>();

    VelocityContext velocityContext = new VelocityContext();
    EventCartridge ec = new EventCartridge();
    ec.addEventHandler((ReferenceInsertionEventHandler)
        (reference, value) -> names.add(reference)
    );
    ec.attachToContext(velocityContext);

    Velocity.evaluate(velocityContext, new StringWriter(), "velocity", template);
    return names;
}

private static Pattern namePattern = Pattern.compile("\\$!?\\{?([a-zA-Z][\\w*\\-])");

public static Set<String> getVariableNames(String template)
{
    Set<String> references = getReferences(template);
    return references.stream()
        .map(r -> namePattern.matcher(r))
        .filter(Matcher::find)
        .map(m -> m.group(1))
        .collect(Collectors.toSet());
}

}

您需要第二种方法来过滤掉任何不是简单变量的东西并清理美元符号和大括号。

于 2018-12-13T22:18:12.450 回答
0

xdocreport项目完成了这项工作。

<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>xdocreport</artifactId>
    <version>1.0.6</version>
</dependency>


StringReader templateReader = new StringReader(stringyTemplateContent);
FieldsExtractor<FieldExtractor> extractor = FieldsExtractor.create();
VelocityFieldsExtractor.getInstance().extractFields(templateReader, templateName, extractor);

for (FieldExtractor fieldExtractor : extractor.getFields()) {
    System.out.println(fieldExtractor.getName());
}

我以他们VelocityFieldsExtractorTestCase为例。

于 2016-12-20T10:05:24.457 回答