我如何通过Velocity修剪空白

我有一个名为render_something的方法,可以创建大量的空格,例如:

#render_something('xxx') 

结果可能是:

  something that generate from redner_something  

实际上我希望它是这样的:

 something that generate from redner_something 

速度有这样的东西吗?

 #trim(#render_something('xxx')) 

我刚刚阅读了关于Velocity Whitespace Gobbling的这篇文章,该文章提出了一些解决方案,包括Velocity Whitespace Truncated By Line Comment 。

这基本上建议通过在每行末尾添加注释来注释掉换行符。 它还建议不要缩进宏中的代码,以防止出现多余的(我最喜欢的单词之一)空格。

TBH它不是一个很好的解决方案,但可能适合您的需求。 简单地将##放在宏中每一行的末尾,这将使事情变得更好……等等

看来只是java native trim()有效。

$someValue.trim()适合我

在创建VelocityEngine的类中,添加如下方法

 public String trim(String str) { return str.trim()/*.replace("\n", "").replace("\r", "")*/; } 

然后将以下内容添加到您创建的VelocityContext中:

  context.put("trimmer", this); 

最后在速度模板中执行以下操作

 $trimmer.trim("#render_something('xxx')") 

它为什么有效?

尽管Velocity的行为已经明确定义,但有时看它是如何工作的可能有点棘手。 需要单独的trim() – 方法来将模板中的char序列转换为Java方法,在该方法中可以调用String上的实际trim()。 据我所知,Velocity内部没有修剪,但你总是可以用这样的技巧回调Java。

双引号是必要的,因为#render_something只是一个宏,而不是函数调用,这意味着宏中的语句结果逐字地放到宏“被执行”的位置。

我挣扎了一段时间才找到一个直接解决空白吞噬的解决方案,所以在这里我最终想出了一个。 它受到了和Vadzim的回答和这个页面的启发http://wiki.apache.org/velocity/StructuredGlobbingResourceLoader

我们可以在网站上找到的StructuredGlobbingResourceLoader有一个复杂的行为,并没有摆脱任何类型的空白,所以我修改它以获得简单的行为:“删除行开头的任何空格,并在以下处添加注释每行的结尾“(这阻止了换行评估)。 filter在加载时应用于输入流。

这种速度模板

 #if($value) the value is $value #end 

变成了

 #if($value)## the value is $value## #end## 

然后,如果你想要换行或行空白的开头,你必须把($ br,“\ n”)和put($ sp,“”)放在你的上下文中,就像Vadzim所解释的那样,并在你的模板中明确地使用它们。 这种做法将允许您保持缩进模板,并具有最大程度的控制。

从这个页面获取类http://wiki.apache.org/velocity/StructuredGlobbingResourceLoader将扩展类更改为您需要的加载器类型(这个使用webapp加载器)将read()方法替换为我提供的代码使用该类作为属性中的资源加载器。 webapp loader的示例:webapp.resource.loader.class = … StructuredGlobbingResourceLoader

 public int read() throws IOException { int ch; switch(state){ case bol: //beginning of line, read until non-indentation character while(true){ ch = in.read(); if (ch!=(int)' ' && ch!=(int)'\t'){ state = State.content; return processChar(ch); } } case content: ch = in.read(); return processChar(ch); //eol states replace all "\n" by "##\n" case eol1: state = State.eol2; return (int)'#'; case eol2: state = State.bol; return (int)'\n'; case eof: return -1; } return -1; } //Return the normal character if not end of file or \n private int processChar(int ch){ switch(ch){ case -1: state = State.eof; return -1; case (int)'\n': state = State.eol1; return (int)'#'; default: return ch; } } 

欢迎任何关于我的实施的反馈

这是我对速度空白吞噬的替代解决方案,允许使用tabbing模板结构。

每个模板文本在自定义ResourceLoader首次加载时进行预处理:

 private String enhanceTemplate(String body) { if (!body.startsWith("##preserveWhitespace")) { body = body.replaceAll("(##.*)?[ \\t\\r]*\\n+[ \\t\\r]*", Matcher.quoteReplacement("##\n")); body = body.trim(); } return body; } 

这只用一个注释换行符替换所有新行和调整空格。

可以使用默认上下文中的$ br和$ sp变量显式插入换行符和尾部空格:

 private static final VelocityContext DEFAULT_CONTEXT = new VelocityContext(new HashMap() {{ put("sp", " "); put("br", "\n"); }}); 

在某些情况下,我必须基本上最小化我的脚本,就像我将js或css。 它运作良好,但人类阅读并不容易。 消除多余空间的另一个选择:

 
    #foreach($par in $bodypars)#set( $parLen = ${_MathTool.toInteger($bodypars.size())} )#set( $parLn = $parLen - 1 )#set( $thClass = 'tb'+${parLn} )#set( $thaClass = '' )#if( $foreach.index == 1 )#set( $thClass = ${thClass}+' selected' )#set( $thaClass = ' selected' )#end#if($foreach.index != 0 && $parLen <= $maxTabs)#set ( $btitle = $_XPathTool.selectSingleNode($par,'item-subtitle') )
  • #if($!btitle && $btitle != '')$_SerializerTool.serialize($btitle, true)#end
  • #end#end

受线条评论截断的Velocity Whitespace的启发,可以使用块注释而不是行注释来获得更好的结果:

 #foreach( $record in $records )#** *##if( $record.id == 0 )#** *##end #end 

使用合适的语法突出显示注释并不是非常突兀。