Статьи

StringTemplate, часть 2: коллекции и группы шаблонов.

Эта статья касается StringTemplate. Если вы никогда не слышали о StringTemplate или « шаблонизаторе », вы можете прочитать либо Часть 1, либо официальную документацию StringTemplate .

Файлы группы шаблонов:

В первой статье мы использовали файл шаблона (.st файл) для хранения нашего определения шаблона. В этих примерах мы определили один шаблон, который охватывает весь файл. Когда все становится сложнее, удобно иметь возможность определять несколько небольших шаблонов в одном файле. StringTemplate называет этот файл «String Template Group» и рекомендует имя файла, оканчивающееся на «.stg».

Пример группы шаблонов строк:

Эта группа шаблонов определяет один шаблон, который принимает два параметра, input1 и input2 . Параметры, передаваемые в шаблон, могут затем использоваться в области содержимого.

Пример шаблона с содержанием:

exampleTemplate(input1, input2) ::= <<
input1 = $input1$
input2 = $input2$
>>

StringTemplateGroups — это удобный способ группировки небольших взаимосвязанных шаблонов. Эти меньшие шаблоны могут быть вложены, как показано ниже.

group group-demo;

outerTemplate(input) ::= <<
In the outer template.
input = $input$ <-- I can see the value of the 'input' parameter and use it.
$innerTemplate(input)$
>>

innerTemplate(nestedInput) ::= <<
The Paramater 'nestedInput' was passed to this template.
nestedInput = $nestedInput$ <-- I can see the value of the 'nestedInput' parameter and use it.
>>

Вот код для использования этой StringTemplateGroup:

StringTemplateGroup group = new StringTemplateGroup(
new FileReader("templates/group-example.stg"), DefaultTemplateLexer.class);

StringTemplate template = group.getInstanceOf("outerTemplate");
template.setAttribute("input", "Hello World");

System.out.println(template.toString());

Форма вывода этого примера будет выглядеть примерно так:

In the outer template.

input = Hello World; <-- I can see the value of the 'input' parameter and use it.

The Paramater 'nestedInput' was passed to this template. I can use it here also.

nestedInput = Hello World <-- I can see the value of the 'nestedInput' parameter and use it.

Коллекции (многозначные атрибуты):

В первой статье я показал несколько основных шаблонных задач. Каждый пример отображал заполнитель на один фрагмент данных. Очень часто сложные структуры требуют работы с коллекциями данных, которые не соответствуют один к одному с заполнителями в шаблоне. В Java, если бы нам пришлось обрабатывать элементы в списке, мы могли бы использовать цикл.

List<String> xmen = Arrays.asList("Jean Gray", "Cyclops",
    "Angel", "Iceman", "Beast");

System.out.println("Original X-Men");
for(String xman : xmen){
    System.out.println(xman);
}

Выход:

Original X-Men
Jean Gray
Cyclops
Angel
Iceman
Beast

Доблестная первая попытка использования StringTemplate может привести к коду, который выглядит следующим образом:

StringTemplate template = new StringTemplate(
"Example 3\nOriginal X-MEN: $xmen$ ");

template.setAttribute("xmen", xmen);

System.out.println(template.toString());

Как видите, мы взяли список строк и просто поместили его в шаблон. К сожалению, это не даст нам такой же результат, как указано выше.

Выход:

Example 3

Original X-MEN: Jean GrayCyclopsAngelIcemanBeast

Здесь происходит то, что мы дали «многозначный атрибут» (коллекцию) для StringTemplate, но не сказали ему, как обрабатывать эти данные. Один из способов сделать это — использовать разделитель.

Example 4:

Original X-MEN members:
$xmen; separator="\n"$

Выход:

Example 4:

Original X-MEN members:
Jean Gray
Cyclops
Angel
Iceman
Beast

Как видите, мы указали разделитель «\ n», что означает перевод строки. Нет ограничений на размер разделителя. Следующее:

$xmen; separator=" \"\$hi, this is a really long separator\$\"\n\n"$ 

даст следующий вывод.

Original X-MEN members:

Jean Gray "$hi, this is a really long separator$"

Cyclops "$hi, this is a really long separator$"

Angel "$hi, this is a really long separator$"

Iceman "$hi, this is a really long separator$"

Beast

Я добавил кавычки и знаки доллара, чтобы подчеркнуть, что вы действительно можете использовать что-либо в разделителе. (Если вы действительно хотите, но я не рекомендую это.)

Применение шаблонов к многозначным атрибутам :

Разделители имеют свое место, но я считаю, что применение шаблона к многозначному атрибуту значительно более гибко и эффективно. Я также чувствую, что это одно из ключевых отличий между StringTemplate и другими шаблонизаторами. Сначала давайте посмотрим на хорошее (плохое?) Старомодное построение строк Java.

// Manual formatting and spacing
StringBuilder builder = new StringBuilder();
builder.append("Example 2 \n");
builder.append("<html><body>\n");
builder.append("<h1>Original X-Men</h1>\n");
builder.append(" <ul>\n");
for(String xman : xmen){
    builder.append(" <li>"+ xman + "</li>\n");
}
builder.append(" </ul>\n");
builder.append("</body></html>\n");

Вот некоторый стандартный код Java для создания блока HTML. Обратите внимание, что здесь есть два разных уровня форматирования. Одним из них является HTML, который имеет такие требования, как открытие и закрытие тегов. Другой фактическое форматирование самого выходного текста. Это сделано для того, чтобы сгенерированный блок читался после его генерации. Всякий раз, когда текст добавляется, обе проблемы форматирования должны быть приняты во внимание. В отличие от многих примеров из первой части, здесь есть некоторый контроль потока. В частности, у нас есть цикл. Когда мы переводим эту логику в шаблон, или, точнее, в два шаблона, мы можем исключить детали цикла.

group list-demo;

htmListExample(xmen) ::= <<
Example 5:
<html>
<body>
<h1>Original X-Men</h1>
<ul>
$xmen:listItem()$
</ul>
</body>
</html>

>>

listItem() ::= <<

<li>$it$</li>
>>

Здесь у нас есть содержимое нашего файла шаблона «list-template-group.stg». Мы определили два шаблона «htmlListExample» и «listItem». Из наших предыдущих примеров мы знаем, что xmen является многозначным атрибутом. Синтаксис: используется для применения шаблона listItem к каждому элементу в списке. Это генерирует следующий вывод:

Выход :

Example 5:
<html>
<body>
<h1>Original X-Men</h1>
<ul>

<li>Jean Gray</li>
<li>Cyclops</li>
<li>Angel</li>
<li>Iceman</li>
<li>Beast</li>
</ul>
</body>
</html>

Как вы можете видеть, нет цикла, нет счетчика цикла, и мы даже не определили переменную во втором шаблоне. StringTemplate делает переменную $ it $ доступной, если вы не указали ее явно. Теперь, если честно, этот вывод не является тем же самым выводом, что и вышеприведенный блок кода Java. В начале списка есть дополнительная новая строка. Большую часть времени я нахожу это «достаточно хорошим» для форматирования «читабельности», но есть способ это исправить. StringTemplate предоставляет функции для разбиения списка на управляемые части. Здесь мы будем использовать first () и rest ().

/**
* HTML example for applying a template to a list using first() and rest()
*/
firstRestExample(xmen) ::= <<

Example 6:
<html>
<body>
<h1>Original X-Men</h1>
<ul>
$first(xmen):firstListItem()$$rest(xmen):listItem()$
</ul>
</body>
</html>
>>

firstListItem() ::= "<li>$it$</li>"

Функция first () возвращает только первый элемент многозначного атрибута. Затем мы применяем шаблон firstListItem () только к первому элементу. Ко всему, кроме первого элемента (возвращаемого rest ()), применен шаблон listItem (). Это генерирует точно такой же вывод, что и блок старомодного кода Java.

Example 6:
<html>
<body>
<h1>Original X-Men</h1>
<ul>
<li>Jean Gray</li>
<li>Cyclops</li>
<li>Angel</li>
<li>Iceman</li>
<li>Beast</li>
</ul>
</body>
</html>

В этом примере использование first и rest было использовано для решения тривиальной проблемы пробелов. В более сложных шаблонах используются функции first (), rest () и т . может решить более важные проблемы. Наконец, вы не ограничены применением только одного шаблона к элементу в списке.

/**
* HTML example for applying multiple templates to a list.
*/
applyMultipleExample(xmen) ::= <<

Example 7:
<html>
<body>
<h1>Original X-Men</h1>
<ul>
$xmen:bold():listItem()$
</ul>
</body>
</html>
>>

/**
* wraps the text in a <span> with a style of bold
*/
bold() ::= <<
<span style="font-weight: bold;">$it$</span>
>>

Для каждого значения многозначного атрибута шаблоны применяются слева направо. В этом случае жирный шрифт применяется сначала, затем элемент списка.

Выход:

Example 7:
<html>
<body>
<h1>Original X-Men</h1>
<ul>

<li><span style="font-weight: bold;">Jean Gray</span></li>
<li><span style="font-weight: bold;">Cyclops</span></li>
<li><span style="font-weight: bold;">Angel</span></li>
<li><span style="font-weight: bold;">Iceman</span></li>
<li><span style="font-weight: bold;">Beast</span></li>
</ul>
</body>

</html>

В этой статье мы рассмотрели файлы группы шаблонов строк, определяя несколько шаблонов в одном файле и применяя шаблоны к атрибутам с несколькими значениями (коллекциям). Если вы хотите узнать больше, я рекомендую официальную документацию StringTemplate . Имеет более подробные объяснения и примеры.

 Исходный код: StringTemplateDemos2.zip

От http://weblogs.java.net/blog/aberrant/archive/2010/06/02/stringtemplate-part-2-collections-and-template-groups