Как я могу обрезать пустые места Velocity
У меня есть метод с именем render_something, который может создать много пробелов, например:
<a href="#">#render_something('xxx')</a>
Результат может быть:
<a href="#">
something that generate from redner_something
</a>
Что на самом деле я хочу, чтобы это было так:
<a href="#">something that generate from redner_something</a>
Есть ли у скорости что-то подобное?
#trim(#render_something('xxx'))
7 ответов
Я только что прочитал эту статью о скоростном гоблинге пробелов, в которой предлагается несколько обходных путей, включая скорость пробелов, усеченную комментариями к строкам.
Это в основном предлагает комментировать разрывы строк, помещая комментарии в конце каждой строки. Он также предлагает не делать отступы кода в ваших макросах, чтобы избежать появления лишних (одно из моих любимых слов) пробелов.
TBH это не очень хорошее решение, но может удовлетворить ваши потребности. Проще говоря ##
в конце каждой строки в вашем макросе, и это будет немного лучше... вроде
Кажется, просто Java родом trim() работает.
$someValue.trim()
работает для меня
Решение
В классе, где вы создаете VelocityEngine, добавьте метод следующим образом
public String trim(String str) {
return str.trim()/*.replace("\n", "").replace("\r", "")*/;
}
затем добавьте следующее в созданный VelocityContext:
context.put("trimmer", this);
и, наконец, в шаблоне скорости сделайте следующее
<a href="#">$trimmer.trim("#render_something('xxx')")</a>
Почему это работает?
Хотя поведение Velocity четко определено, иногда бывает сложно увидеть, как оно работает. Отдельный метод trim() необходим для получения последовательности символов из шаблона в метод Java, где вы можете вызвать фактический trim() для String. Насколько я знаю, внутри Velocity нет обрезки, но вы всегда можете перезвонить в Java с помощью таких хитростей, как этот.
Двойные кавычки необходимы, потому что #render_something - это просто макрос, а не вызов функции, это означает, что результаты операторов в макросе дословно помещаются в точку, где макрос "выполняется".
Некоторое время я изо всех сил пытался найти простое решение для сожжения пустого пространства, поэтому вот тот, который я наконец-то придумал. Он вдохновлен ответом Вадима и этой страницы http://wiki.apache.org/velocity/StructuredGlobbingResourceLoader
StructuredGlobbingResourceLoader, который мы можем найти на веб-сайте, имеет сложное поведение и не избавляется от каких-либо пробелов, поэтому я изменил его, чтобы получить простое поведение: "Удалите все пробелы в начале строк и добавьте комментарий в конец каждой строки " (что препятствует оценке переноса строки). Фильтр применяется к входному потоку во время загрузки.
Этот вид скоростного шаблона
#if($value)
the value is $value
#end
превращается в
#if($value)##
the value is $value##
#end##
Затем, если вы хотите иметь разрывы строк или начало пробелов, вы должны поместить ($br,"\n") и поставить ($sp," ") в свой контекст, как объяснил Вадим, и явно использовать их в своем шаблоне., Этот способ позволит вам сохранить шаблоны с отступом, с максимальным контролем.
возьмите класс с этой страницы http://wiki.apache.org/velocity/StructuredGlobbingResourceLoader измените расширенный класс на тот тип загрузчика, который вам нужен (этот использует загрузчик webapp), замените метод read() на код, который я предоставляю класс как ваш загрузчик ресурсов в ваших свойствах. Пример загрузчика веб-приложений: 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;
}
}
Любые отзывы о моей реализации приветствуются
Вдохновленные скоростным пробелом, усеченным комментарием к строке, можно использовать блочные комментарии вместо комментариев к строке для лучшего результата:
#foreach( $record in $records )#**
*##if( $record.id == 0 )#**
*##end
#end
С приличной подсветкой синтаксиса комментарии не очень навязчивы.
В некоторых случаях мне приходилось существенно минимизировать мой скрипт, как если бы я использовал js или css. Это работает хорошо, хотя людям не так легко читать. Еще один вариант устранения лишнего пространства:
<ul class="tabs">#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') )<li class="${thClass}">#if($!btitle && $btitle != '')<a href="#" class="#cleanString($btitle.value.toLowerCase())${thaClass}">$_SerializerTool.serialize($btitle, true)</a>#end</li>#end#end</ul>
Вот мое альтернативное решение для скоростного гоблирования пробелов, которое позволяет вкладывать структуру шаблона.
Каждый текст шаблона предварительно обрабатывается при первой загрузке в пользовательском 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<String, String>() {{
put("sp", " ");
put("br", "\n");
}});
Вы можете использовать стандартную обрезку java, обращая внимание на вашу переменную, если это объект, а не строка.
$string.trim() //work fine
$object.trim() //exception
Хорошего дня!