【问题标题】:Getting the variables in Velocity获取 Velocity 中的变量
【发布时间】:2018-12-14 06:59:55
【问题描述】:

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

【问题讨论】:

    标签: java velocity


    【解决方案1】:

    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 是任何引用。如果您有如下模板:

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

    此代码打印出来:$var$primate

    【讨论】:

      【解决方案2】:

      我能想到的唯一方法是你在速度引擎中添加这样的东西:

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

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

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

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

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

      HashMap map = (HashMap)context.get("parameters");
      for (String key : map.keySet()) {
          // ...
      }
      

      【讨论】:

        【解决方案3】:

        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 为例。

        【讨论】:

          【解决方案4】:

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

          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());
          }
          
          }
          

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

          【讨论】:

          • "ec.addEventHandler((ReferenceInsertionEventHandler) (reference, value) -> names.add(reference) );" ==> names.add 返回 boolean 但 object 是预期的。你能修复代码吗??
          猜你喜欢
          • 1970-01-01
          • 2012-01-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-11
          相关资源
          最近更新 更多