当对 XML 以外的树使用 #recurse 时,我需要数据模型的 Freemarker 文档
I need Freemarker documentation for data model when using #recurse with trees other than XML
我正在尝试在 Freemarker 中处理树结构,并想使用 #recurse、#visit 指令,但我找不到任何关于如何设置数据模型的好文档。我能看到的唯一示例是为 XML 结构创建数据模型的示例。我不需要这么详细。我的树很简单。
为了测试我需要的功能,我构建了一个单元测试,但是当我 运行 它时,我得到
FreeMarker template error:
For "." left-hand operand: Expected a hash, but this has evaluated to a node
这里是源代码:
public class FreemarkerXmlTests {
static class Element implements TemplateNodeModel {
private final String name;
private final String text;
private Element parent;
private final List<Element> elements = new ArrayList<>();
public Element(String name) {
this(name, null);
}
public Element(String name, String text) {
this.name = name;
this.text = text;
}
public void add(Element element) {
element.parent = this;
this.elements.add(element);
}
public List<Element> getElements() {
return this.elements;
}
public String getName() {
return this.name;
}
public String getText() {
return this.text;
}
public String getTitle() {
return this.name;
}
public TemplateModel get(String key) {
return null;
}
@Override
public TemplateNodeModel getParentNode() throws TemplateModelException {
return this.parent;
}
@Override
public TemplateSequenceModel getChildNodes() throws TemplateModelException {
// TODO Auto-generated method stub
return new SimpleSequence(this.elements, cfg.getObjectWrapper());
}
@Override
public String getNodeName() throws TemplateModelException {
return this.name;
}
@Override
public String getNodeType() throws TemplateModelException {
return this.name;
}
@Override
public String getNodeNamespace() throws TemplateModelException {
return null;
}
}
private static Configuration cfg;
private static final String myTestTemplate = "<#recurse doc>\r\n" +
"\r\n" +
"<#macro book>\r\n" +
" Book element with title ${.node.title} \r\n" +
" <#recurse>\r\n" +
" End book\r\n" +
"</#macro>\r\n" +
"\r\n" +
"<#macro title>\r\n" +
" Title element\r\n" +
"</#macro>\r\n" +
"\r\n" +
"<#macro chapter>\r\n" +
" Chapter element with title: ${.node.title}\r\n" +
"</#macro>";
@BeforeClass
public static void classInit() throws IOException {
StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
stringTemplateLoader.putTemplate("myTestTemplate", myTestTemplate);
cfg = new Configuration(Configuration.VERSION_2_3_29);
cfg.setTemplateLoader(stringTemplateLoader);
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
cfg.setWrapUncheckedExceptions(true);
cfg.setFallbackOnNullLoopVariable(false);
}
@Test
public void basicXmlTest() throws TemplateException, IOException {
Element doc = new Element("doc");
Element book = new Element("book");
book.add(new Element("title", "Test Book"));
doc.add(book);
Element chapter1 = new Element("chapter");
chapter1.add(new Element("title", "Ch1"));
chapter1.add(new Element("para", "p1.1"));
chapter1.add(new Element("para", "p1.2"));
chapter1.add(new Element("para", "p1.3"));
book.add(chapter1);
Element chapter2 = new Element("chapter");
chapter2.add(new Element("title", "Ch2"));
chapter2.add(new Element("para", "p2.1"));
chapter2.add(new Element("para", "p2.2"));
chapter2.add(new Element("para", "p2.3"));
book.add(chapter2);
Map<String, Object> root = new HashMap<>();
// Put string "user" into the root
root.put("doc", doc);
Template temp = cfg.getTemplate("myTestTemplate");
Writer out = new OutputStreamWriter(System.out);
temp.process(root, out);
}
有什么想法吗?
看看 freemarker.template.TemplateNodeModel
interface. Your objects have to implement that, or they have to be wrapped (via the ObjectWrapper
) into a TemplateModel
的实现。然后 #recurse
/#visit
/?parent
/?children
/等等。将与他们合作。
下面是一个实现的例子TemplateNodeModel
for traversing JSON: https://github.com/freemarker/fmpp/blob/master/src/main/java/fmpp/models/JSONNode.java
上面使用的一些模板:
https://github.com/freemarker/fmpp/tree/master/src/test/resources/tests/dl_json/src
从 .
运算符开始,您需要实现 TemplateHashModel
(或其子接口,如 TemplateHashModelEx2
)。
借助 ddekany 发布的示例,我添加了以下内容:
- 为元素实现 TemplateHashModel class
static class Element implements TemplateNodeModel, TemplateHashModel {
- 元素的方法 class 并且单元测试有效:
@Override
public TemplateModel get(String key) throws TemplateModelException {
switch (key) {
case "title":
case "name":
return cfg.getObjectWrapper().wrap(this.name);
default:
throw new TemplateModelException("unknown hash get: " + key);
}
}
我正在尝试在 Freemarker 中处理树结构,并想使用 #recurse、#visit 指令,但我找不到任何关于如何设置数据模型的好文档。我能看到的唯一示例是为 XML 结构创建数据模型的示例。我不需要这么详细。我的树很简单。
为了测试我需要的功能,我构建了一个单元测试,但是当我 运行 它时,我得到
FreeMarker template error:
For "." left-hand operand: Expected a hash, but this has evaluated to a node
这里是源代码:
public class FreemarkerXmlTests {
static class Element implements TemplateNodeModel {
private final String name;
private final String text;
private Element parent;
private final List<Element> elements = new ArrayList<>();
public Element(String name) {
this(name, null);
}
public Element(String name, String text) {
this.name = name;
this.text = text;
}
public void add(Element element) {
element.parent = this;
this.elements.add(element);
}
public List<Element> getElements() {
return this.elements;
}
public String getName() {
return this.name;
}
public String getText() {
return this.text;
}
public String getTitle() {
return this.name;
}
public TemplateModel get(String key) {
return null;
}
@Override
public TemplateNodeModel getParentNode() throws TemplateModelException {
return this.parent;
}
@Override
public TemplateSequenceModel getChildNodes() throws TemplateModelException {
// TODO Auto-generated method stub
return new SimpleSequence(this.elements, cfg.getObjectWrapper());
}
@Override
public String getNodeName() throws TemplateModelException {
return this.name;
}
@Override
public String getNodeType() throws TemplateModelException {
return this.name;
}
@Override
public String getNodeNamespace() throws TemplateModelException {
return null;
}
}
private static Configuration cfg;
private static final String myTestTemplate = "<#recurse doc>\r\n" +
"\r\n" +
"<#macro book>\r\n" +
" Book element with title ${.node.title} \r\n" +
" <#recurse>\r\n" +
" End book\r\n" +
"</#macro>\r\n" +
"\r\n" +
"<#macro title>\r\n" +
" Title element\r\n" +
"</#macro>\r\n" +
"\r\n" +
"<#macro chapter>\r\n" +
" Chapter element with title: ${.node.title}\r\n" +
"</#macro>";
@BeforeClass
public static void classInit() throws IOException {
StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
stringTemplateLoader.putTemplate("myTestTemplate", myTestTemplate);
cfg = new Configuration(Configuration.VERSION_2_3_29);
cfg.setTemplateLoader(stringTemplateLoader);
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
cfg.setWrapUncheckedExceptions(true);
cfg.setFallbackOnNullLoopVariable(false);
}
@Test
public void basicXmlTest() throws TemplateException, IOException {
Element doc = new Element("doc");
Element book = new Element("book");
book.add(new Element("title", "Test Book"));
doc.add(book);
Element chapter1 = new Element("chapter");
chapter1.add(new Element("title", "Ch1"));
chapter1.add(new Element("para", "p1.1"));
chapter1.add(new Element("para", "p1.2"));
chapter1.add(new Element("para", "p1.3"));
book.add(chapter1);
Element chapter2 = new Element("chapter");
chapter2.add(new Element("title", "Ch2"));
chapter2.add(new Element("para", "p2.1"));
chapter2.add(new Element("para", "p2.2"));
chapter2.add(new Element("para", "p2.3"));
book.add(chapter2);
Map<String, Object> root = new HashMap<>();
// Put string "user" into the root
root.put("doc", doc);
Template temp = cfg.getTemplate("myTestTemplate");
Writer out = new OutputStreamWriter(System.out);
temp.process(root, out);
}
有什么想法吗?
看看 freemarker.template.TemplateNodeModel
interface. Your objects have to implement that, or they have to be wrapped (via the ObjectWrapper
) into a TemplateModel
的实现。然后 #recurse
/#visit
/?parent
/?children
/等等。将与他们合作。
下面是一个实现的例子TemplateNodeModel
for traversing JSON: https://github.com/freemarker/fmpp/blob/master/src/main/java/fmpp/models/JSONNode.java
上面使用的一些模板: https://github.com/freemarker/fmpp/tree/master/src/test/resources/tests/dl_json/src
从 .
运算符开始,您需要实现 TemplateHashModel
(或其子接口,如 TemplateHashModelEx2
)。
借助 ddekany 发布的示例,我添加了以下内容:
- 为元素实现 TemplateHashModel class
static class Element implements TemplateNodeModel, TemplateHashModel {
- 元素的方法 class 并且单元测试有效:
@Override
public TemplateModel get(String key) throws TemplateModelException {
switch (key) {
case "title":
case "name":
return cfg.getObjectWrapper().wrap(this.name);
default:
throw new TemplateModelException("unknown hash get: " + key);
}
}