Java FreeMarker:使用宏时保持标识
我正在使用FreeMarker模板引擎从Web服务的抽象描述生成一些php类。我的问题是,当我在FreeMarker模板中调用宏时,宏会在调用宏之前插入没有左边空白的文本 示例Template.ftl:Java FreeMarker:使用宏时保持标识,java,code-generation,freemarker,Java,Code Generation,Freemarker,我正在使用FreeMarker模板引擎从Web服务的抽象描述生成一些php类。我的问题是,当我在FreeMarker模板中调用宏时,宏会在调用宏之前插入没有左边空白的文本 示例Template.ftl: <?php class ${class.name} { <@docAsComment class.doc/> <#list class.fields as field> $${field.name};
<?php
class ${class.name} {
<@docAsComment class.doc/>
<#list class.fields as field>
$${field.name};
</#list>
<#-- ... -->
}
?>
<#macro docAsComment doc>
/*
<#if doc.title != "">
* ${doc.title}
</#if>
<#list doc.content as content>
<#if content != ""> * ${content}</#if>
</#list>
*/
</#macro>
/*
*${doc.title}
*${content}
*/
这将生成如下内容:
<?php
class foo {
/*
* foo
* bar foo, bla
*/
$a;
$b;
}
?>
<@docAsComment class.doc 1/>
<#macro docAsComment doc indent=1>
<#local spc>${""?left_pad(indent * 4)}</#local>
${spc}/*
<#if doc.title != "">
${spc}* ${doc.title}
</#if>
<#list doc.content as content>
<#if content != "">${spc} * ${content}</#if>
</#list>
${spc}*/
</#macro>
一种解决方案是,将前导空格作为参数提交给宏,但这只会使模板更不可读。有更好的解决方案吗?似乎总是在代码生成中相同的缩进级别调用
docAsComment
。可以将缩进烘焙到宏中
如果注释的缩进是可变的,则必须传入缩进级别。我不理解你关于模板更难阅读的评论。它确实使宏变得更复杂一些
调用如下所示:
<?php
class foo {
/*
* foo
* bar foo, bla
*/
$a;
$b;
}
?>
<@docAsComment class.doc 1/>
<#macro docAsComment doc indent=1>
<#local spc>${""?left_pad(indent * 4)}</#local>
${spc}/*
<#if doc.title != "">
${spc}* ${doc.title}
</#if>
<#list doc.content as content>
<#if content != "">${spc} * ${content}</#if>
</#list>
${spc}*/
</#macro>
宏将更改为以下内容:
<?php
class foo {
/*
* foo
* bar foo, bla
*/
$a;
$b;
}
?>
<@docAsComment class.doc 1/>
<#macro docAsComment doc indent=1>
<#local spc>${""?left_pad(indent * 4)}</#local>
${spc}/*
<#if doc.title != "">
${spc}* ${doc.title}
</#if>
<#list doc.content as content>
<#if content != "">${spc} * ${content}</#if>
</#list>
${spc}*/
</#macro>
${“?左焊盘(缩进*4)}
${spc}/*
${spc}*${doc.title}
${spc}*${content}
${spc}*/
还不错,真的。通过缩进宏,可以使其更易于阅读:
<#macro docAsComment doc indent=1>
<#local spc>${""?left_pad(indent * 4)}</#local>
${spc}/*<#lt>
<#if doc.title != "">
${spc}* ${doc.title}<#lt>
</#if>
<#list doc.content as content>
<#if content != "">${spc} * ${content}</#if><#lt>
</#list>
${spc}*/<#lt>
</#macro>
${“?左焊盘(缩进*4)}
${spc}/*
${spc}*${doc.title}
${spc}*${content}
${spc}*/
这类问题(动态缩进)的通用解决方案是一个过滤器,它(基本)理解您生成的语言(PHP)并重新缩进代码。您可以将该过滤器实现为包装实际输出的编写器。如果它观察{
、}
、/*
和*/
标记的位置(我不确定),可能就足够了
另一个更容易实现的解决方案是,通过实现TemplateDirectiveModel
来创建自定义FreeMarker指令,该指令通过在每一行的开头添加或删除作为参数指定给它的空格量,过滤嵌套内容中生成的输出。然后你可以做一些类似的事情:
<@indent spaces=4>
...
</@indent>
...
使用此选项将使模板更加复杂,但仍然不像在每行中插入缩进那样嘈杂。今天,可以使用
。政府对此有如下说法:
对于具有nt指令的单行,可以禁用空白剥离(对于不修剪)
根据,在以前的版本中,只包含FTL标记的行会被修剪,但
和自定义指令除外(如
)。但在V2.3中,他们改变了这种行为,总是修剪这样的线条。因此,在使用宏时,可以将
放在行上以防止修剪,从而保持缩进
<#macro test>
...<#t>
</#macro>
Example:
- <@test /><#nt>
您可以看到,在宏中,我定义了
,这是因为宏内部的新行不会被修剪,并且总是在
它所在的位置给出新行,因此在一部分中,我们修剪空白,在另一部分中,我们保留它
编辑:
值得一提的是,出于某种原因,此仅适用于一行。如果宏中有多行,它只保留第一行的缩进。到目前为止,我还没有找到解决这个问题的方法,但我为此创建了
例如:
<#macro test>
...
wow
</#macro>
Example:
- <@test><#nt>
对于那些希望在导入的宏前面加上一些空格缩进的人,下面有一个类来执行这项工作:
public final static class IndentDirective
implements TemplateDirectiveModel
{
private static final String COUNT = "count";
public void execute(Environment environment, Map parameters, TemplateModel[] templateModels,
TemplateDirectiveBody body)
throws TemplateException, IOException
{
Integer count = null;
final Iterator iterator = parameters.entrySet().iterator();
while (iterator.hasNext())
{
final Map.Entry entry = (Map.Entry) iterator.next();
final String name = (String) entry.getKey();
final TemplateModel value = (TemplateModel) entry.getValue();
if (name.equals(COUNT) == true)
{
if (value instanceof TemplateNumberModel == false)
{
throw new TemplateModelException("The \"" + COUNT + "\" parameter " + "must be a number");
}
count = ((TemplateNumberModel) value).getAsNumber().intValue();
if (count < 0)
{
throw new TemplateModelException("The \"" + COUNT + "\" parameter " + "cannot be negative");
}
}
else
{
throw new TemplateModelException("Unsupported parameter '" + name + "'");
}
}
if (count == null)
{
throw new TemplateModelException("The required \"" + COUNT + "\" parameter" + "is missing");
}
final String indentation = StringUtils.repeat(' ', count);
final StringWriter writer = new StringWriter();
body.render(writer);
final String string = writer.toString();
final String lineFeed = "\n";
final boolean containsLineFeed = string.contains(lineFeed) == true;
final String[] tokens = string.split(lineFeed);
for (String token : tokens)
{
environment.getOut().write(indentation + token + (containsLineFeed == true ? lineFeed : ""));
}
}
}
谢谢你的回复!“使模板更难阅读”,我的意思几乎和你想的一样,它使宏更复杂,更不容易解释。提交缩进级别似乎是解决此问题的最合理的方法。您始终可以在宏上添加注释标题,以帮助澄清它的作用。您的代码段中有一个类型,它应该是:..
${”“?left_pad(indent*4)}
..
@klingt.net谢谢!已修复。您建议如何将行拆分?应通过TemplateDirectiveModel
而不是通过#宏
实现缩进
指令。如果您查看TemplateDirectiveModel
API,您将看到如何实现它。是吗?:)然后你也可以做
,然后在上面使用正则表达式(通过?替换)来实现同样的效果。我想这就是你可能要做的。我喜欢RAD(纯FTL快速简便)。TemplateDirectiveModel
最终会更清晰,但我的首选是避免将逻辑移到Java类中,直到1)功能的需求完全确定,2)在FTL中实现逻辑真的不可理解(在Java中会更清晰)。