如何反省自由标记模板以找出它使用的变量?

我不确定这是否是一个可解决的问题,但假设我有一个freemarker模板,我希望能够向模板询问它使用的变量。

出于我的目的,我们可以假设freemarker模板非常简单 – 只是“根级”条目(这种模板的模型可以是一个简单的Map)。 换句话说,我不需要处理调用嵌套结构等的模板。

我有同样的任务从java端获取模板中的变量列表,除了使用reflection之外,没有找到任何好的方法。 我不确定是否有更好的方法来获取这些数据,但这是我的方法:

 public Set referenceSet(Template template) throws TemplateModelException { Set result = new HashSet<>(); TemplateElement rootTreeNode = template.getRootTreeNode(); for (int i = 0; i < rootTreeNode.getChildCount(); i++) { TemplateModel templateModel = rootTreeNode.getChildNodes().get(i); if (!(templateModel instanceof StringModel)) { continue; } Object wrappedObject = ((StringModel) templateModel).getWrappedObject(); if (!"DollarVariable".equals(wrappedObject.getClass().getSimpleName())) { continue; } try { Object expression = getInternalState(wrappedObject, "expression"); switch (expression.getClass().getSimpleName()) { case "Identifier": result.add(getInternalState(expression, "name").toString()); break; case "DefaultToExpression": result.add(getInternalState(expression, "lho").toString()); break; case "BuiltinVariable": break; default: throw new IllegalStateException("Unable to introspect variable"); } } catch (NoSuchFieldException | IllegalAccessException e) { throw new TemplateModelException("Unable to reflect template model"); } } return result; } private Object getInternalState(Object o, String fieldName) throws NoSuchFieldException, IllegalAccessException { Field field = o.getClass().getDeclaredField(fieldName); boolean wasAccessible = field.isAccessible(); try { field.setAccessible(true); return field.get(o); } finally { field.setAccessible(wasAccessible); } } 

我在演示模板内省时所做的示例项目可以在github上找到: https : //github.com/SimY4/TemplatesPOC.git

这可能是晚了,但是如果其他人遇到这个问题:你可以使用’data_model’和’globals’来检查模型 – data_model只包含模型提供的值,而globals也包含模板中定义的任何变量。 您需要在点前添加特殊变量 – 所以要访问全局变量,请使用$ {。globals}

有关其他特殊变量,请参阅http://freemarker.sourceforge.net/docs/ref_specvar.html

另一种从java获取变量的方法。 这只是尝试处理模板并捕获InvalidReferenceException以查找freemarker-template中的所有变量

  /** * Find all the variables used in the Freemarker Template * @param templateName * @return */ public Set getTemplateVariables(String templateName) { Template template = getTemplate(templateName); StringWriter stringWriter = new StringWriter(); Map dataModel = new HashMap<>(); boolean exceptionCaught; do { exceptionCaught = false; try { template.process(dataModel, stringWriter); } catch (InvalidReferenceException e) { exceptionCaught = true; dataModel.put(e.getBlamedExpressionString(), ""); } catch (IOException | TemplateException e) { throw new IllegalStateException("Failed to Load Template: " + templateName, e); } } while (exceptionCaught); return dataModel.keySet(); } private Template getTemplate(String templateName) { try { return configuration.getTemplate(templateName); } catch (IOException e) { throw new IllegalStateException("Failed to Load Template: " + templateName, e); } } 

我解决了这个非常简单的用例(仅使用平面数据结构,没有嵌套(例如:$ {parent.child}),列表或更具体)与虚拟数据提供者:

 public class DummyDataProvider extends HashMap { private static final long serialVersionUID = 1; public final Set variables = new HashSet<>(); @SuppressWarnings("unchecked") @Override public V get(Object key) { variables.add(key.toString()); return (V) key; } } 

您可以将其用于处理模板,并在完成时设置variables包含您的变量。

这是一种非常简单的方法,当然需要改进,但你明白了。

我遇到了同样的问题,发布的解决方案都没有对我有意义。 我带来的是插入TemplateExceptionHandler自定义实现。 例:

 final private List missingReferences = Lists.newArrayList(); final Configuration cfg = new Configuration(Configuration.VERSION_2_3_23); cfg.setTemplateExceptionHandler(new TemplateExceptionHandler() { @Override public void handleTemplateException(TemplateException arg0, Environment arg1, Writer arg2) throws TemplateException { if (arg0 instanceof InvalidReferenceException) { missingReferences.add(arg0.getBlamedExpressionString()); return; } throw arg0; } } Template template = loadTemplate(cfg, templateId, templateText); StringWriter out = new StringWriter(); try { template.process(templateData, out); } catch (TemplateException | IOException e) { throw new RuntimeException("oops", e); } System.out.println("Missing references: " + missingReferences); 

点击此处了解更多信息: https : //freemarker.apache.org/docs/pgui_config_errorhandling.html

在模板上执行以下正则表达式:

 (?<=\$\{)([^\}]+)(?=\}) 
  • (?<= \ $ \ {)匹配后跟$ {的所有内容
  • ([^ \}] +)匹配任何不包含的字符串}
  • (?= \})匹配之前的所有内容}