|
|
|
Template engine
|
|||
|---|---|---|---|
|
#18+
Добрый день. Нужен Template engine для java, не заточенный для WEB. Нужен для формирования сообщений по различным каналам (СМС, E-mail, соц. сети и т.п.) Движок должен поддерживать арифметические операции, форматирование (числа, даты), вложенные шаблоны, загрузчик шаблонов из произвольного хранилища (не только файлы). Также ветвления, работу со списками (массивами). Но, в принципе, готов рассмотреть и легковесный, типа Mustache. Но самое основное требование - движок должен уметь определить по шаблону (включая вложенные шаблоны) список переменных, которые нужны для формирования Data Model. Есть ветвление, то надо собрать переменные по всем веткам (то есть все, что есть в шаблоне). Уже посмотрел FreeMarker, Velocity, Mustache ... но, увы, ни один из них не позволяет получить список переменных на этапе разбора шаблона. Они все работают так: уже на этапе шаблонизации, когда известна DataModel, если в шаблоне встретилась переменная X - вызвали DataModel.get(X), то есть в порядке объявления переменных в шаблоне. Мне это не подходит, у меня сама DataModel должна быть подготовлена на основе переменных, содержащихся в шаблоне. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.08.2017, 19:00 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVAНужен Template engine для javaJavaScript engine ! Или любой другой скриптовый язык имхо ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.08.2017, 20:40 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVAОни все работают так: уже на этапе шаблонизации, когда известна DataModel, если в шаблоне встретилась переменная X - вызвали DataModel.get(X), то есть в порядке объявления переменных в шаблоне. Не понял. Но по крайней мере для FreeMarker это утверждение неправильно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.08.2017, 21:51 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
Partisan M, Поправлю утверждение: FreeMarker, как и все остальные, парсит шаблон, стоит дерево токенов, только извлечь оттуда переменные шаблона не получится (в общем случае). Затем, на этапе заполнения шаблона он запрашивает значения переменных из map (DataModel). Вот здесь можно их отлавливать, но это будет происходить: - не на этапе парсинга - в порядке объявления переменных в шаблоне - при наличии ветвлений, запрошены будут не все переменные ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 10:18 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
Usman, нужно что-то для Java, template engine вроде для этого и предназначен. Берем параметризованный шаблон, парсим его, внедряем значения переменных. дело за малым - получить список этих самых переменных из шаблона :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 10:20 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVAнужно что-то для Java The Nashorn Java API LVAБерем параметризованный шаблон, парсим его, внедряем значения переменных. дело за малым - получить список этих самых переменных из шаблона :) https://wiki.openjdk.java.net/display/Nashorn/Nashorn extensions Код: javascript 1. 2. 3. 4. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 10:48 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
Usman, шаблон в виде кода ? не хотелось бы. и я не понял, как предлагается решить обозначенную мной проблему: получить список этих самых переменных из шаблона ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 13:00 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
Топик прозвучал как задание фрилансеру на разработку. Автор, ты хочешь чтобы тебе тут бесплатно все это разработали? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 13:08 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
mayton, я вроде по-русски написал, что ищу template engine, удовлетворяющий некоторым критериям. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 13:20 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVAя вроде по-русски написал, что ищу template engine, удовлетворяющий некоторым критериям. На stackoverflow есть пример как рефлексией из Freemarker-а вытягивают переменные. Если рефлексией не хочется, то не грех и дописать API в Opensource либу. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 13:22 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVAно, увы, ни один из них не позволяет получить список переменных на этапе разбора шаблона . Это требование - вообще треш какой-то. Боюсь что с такой спецификой как раз готовый template engine мы не найдем. Вот по этому вопрос звучит как ТЗ на разработку. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 13:27 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
BlazkowiczНа stackoverflow есть пример как рефлексией из Freemarker-а вытягивают переменные. Если рефлексией не хочется, то не грех и дописать API в Opensource либу. вчера разбирался с этим. Если вкратце - то это не вариант. По вложенным шаблонам рефлексией ничего не вытянешь, на этапе парсинга они не анализируются. Ну и там не только рефлексия, там еще знание о названиях кучи внутренних классов требуется. У разных классов разные поля, из которых нужно рефлексией тянуть инфу. В примере обошлись несколькими - а на самом деле их там десятки (все это надо в switch прописать). Даже если все это довести до ума (то есть повторить снаружи знание внутренностей FreeMarker), то с выходом каждой новой версии все это надо заново тестировать на предмет обратной совместимости и на предмет наличия чего то нового. Нет, это не рабочий вариант. Дописать в либу - ну тут во время упирается. Да и не факт, что это удастся пропихнуть. Пока надо посмотреть, что есть на рынке, смотрю потихоньку, в фоновом режиме. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 14:46 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVA, А почему не кодом? Шаблон - это функция, которая получает список параметров (модель) и возвращает строку. Шаблон верхнего уровня может вызывать шаблоны нижнего уровня(просто вызывая их как функции) и передавая в них параметры. Писать лучше на языке, который поддерживает многострочные строки и интерполяцию, groovy к примеру или яваскрипт. Еще вариант - Scala, посмотрите на Twirl template engine для вдохновения. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 15:23 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
scf, - шаблоны уже реализованы в упрощенном виде и работают в проме. Хотелось бы сохранить совместимость. - любой код - это возможность сделать что-то нежелательное, умышленно или нет. То есть это может быть и небезопасно, и с точки зрения производительности - неоптимально. Зачем давать пользователю такую возможность ? Пока есть возможность без этого обойтись, надо обходиться, имхо ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 16:10 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVA, Так совместимость или смена шаблонизатора? И, имхо, давать юзерам самим шаблоны редактировать - утопия. Ладно, если будут вопросы, пишите. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 16:19 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
scf, сейчас сторонний шаблонизатор не используется вообще. Логика очень простая. Просто идет усложнение логики, и не хотелось бы самому писать то, что уже умеют все другие шаблонизаторы. Вот только одна проблема неожиданная всплыла. Никак не мог предположить заранее , что получение переменных из шаблона - это непосильная задача ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 16:51 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVA, В простейших случаях можно воспользоваться регуляркой. Но в более сложных, например (Freemarker): Код: html 1. 2. 3. 4. 5. 6. => Код: html 1. 2. 3. 4. 5. 6. или с условиями: Код: html 1. 2. 3. 4. 5. 6. 7. Это практически невозможно. Но Вы можете помечать каждый обработанный шаблон неким ID и по нему уже получать весь список параметров/значений (properties/map), которые были переданы на вход шаблонизатора. Все параметры должны быть сохранены, например, в базе (можно даже в сериализированном виде) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 17:10 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
Usman, на вход шаблонизатора надо передать именно те значения, которые есть в шаблоне, в этом вся фишка. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 17:26 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVA, Интересно, а как они попали в шаблон, если все эти значения раскидывает шаблонизатор? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 17:34 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
Usman, тут, наверное, какое то недопонимание, только я не пойму, где именно. на вход шаблонизатора передается и шаблон, и значения тех переменных, которые есть в шаблоне. эти значения нужно получить (это - отдельный алгоритм, который требует оптимизации), но для этого надо сперва извлечь названия переменных из шаблона. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 18:17 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVAназвания переменныхТак это ж placeholder'ы. Их можно вытащить регуляркой. Они обычно обозначаются примерно таким образом: ${<parameter-name>} ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 18:23 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVAUsman, на вход шаблонизатора надо передать именно те значения, которые есть в шаблоне, в этом вся фишка. Ну у вас какая-то специфическая задача, нетипичная для шаблонизаторов. Не настаиваю, но возможно все-таки вы уперлись в свою реализацию и не видите как сделать иначе? В теории шаблонизатору на вход подается файл с плейсхолдерами и некий контекст или модель, из которой можно вытянуть все значения плейсхолдеров. Вам же все value нужны на момент начала парсинга.. Зачем? По идее изменить шаблон вы будете не в состоянии, раз вы уже начали вычитку шаблона и вам нужны все переменные ЭТОГО шаблона. В чем профит? Единственное что я могу предположить, что получение данных из контекста тяжелое, и вы хотите получить все значения махом а потом в шаблонизаторе пробежаться без задержек. Но так ли страшен лукап значений из контекста? Прошу прощения если нафантазировал :) Просто хотелось бы понять исток задачи, сам неоднократно оказывался в ситуации когда замыленный взгляд не позволял увидеть тривиальную альтернативу ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 18:25 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
UsmanLVAназвания переменныхТак это ж placeholder'ы. Их можно вытащить регуляркой. Они обычно обозначаются примерно таким образом: ${<parameter-name>} А вложенные как вытянуть? Да а еще если они зависят от значений плейсхолдеров?(хотя тут ничего не поможет ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 18:27 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVA, у вас цель какая в конечном итоге? Не вычислять все подряд? ну передавайте шаблонизатору свой java.util.Map в котором лениво вычисляются значения, делов-то. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 18:29 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
забыл никНу у вас какая-то специфическая задача, нетипичная для шаблонизаторов. Не настаиваю, но возможно все-таки вы уперлись в свою реализацию и не видите как сделать иначе? В теории шаблонизатору на вход подается файл с плейсхолдерами и некий контекст или модель, из которой можно вытянуть все значения плейсхолдеров. Вам же все value нужны на момент начала парсинга.. Зачем? По идее изменить шаблон вы будете не в состоянии, раз вы уже начали вычитку шаблона и вам нужны все переменные ЭТОГО шаблона. В чем профит? Единственное что я могу предположить, что получение данных из контекста тяжелое, и вы хотите получить все значения махом а потом в шаблонизаторе пробежаться без задержек. Но так ли страшен лукап значений из контекста? Прошу прощения если нафантазировал :) Просто хотелось бы понять исток задачи, сам неоднократно оказывался в ситуации когда замыленный взгляд не позволял увидеть тривиальную альтернативу В целом правильно нафантазировали -) получение значений происходит путем взаимодействия с другими сервисами. Все сразу вообще нельзя получить. Зная параметры заранее, можно составить оптимальный план получения значений параметров, минимизировав количество обращений по сети. Это важно. А сами параметры при этом зависимые. В общем, это отдельная задача оптимизации. Если делать ленивую мапу, то все вызовы будут последовательные, и общее их количество может быть чрезмерным. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 18:54 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
UsmanТак это ж placeholder'ы. Их можно вытащить регуляркой. Они обычно обозначаются примерно таким образом: ${<parameter-name>} это сейчас вытаскиваю регуляркой, потому что шаблон примитивный. а когда добавятся вложенные шаблоны, циклы, временные переменные, ветвления, арифметика, форматирование и т.д, и .т.п, то не вытащить уже ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 18:58 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVAто не вытащить ужепри желании можно вытащить все . ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 19:04 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVAВсе сразу вообще нельзя получить.форс-мажор для шаблонизатора (:LVAВ общем, это отдельная задача оптимизации.которая не относится к теме Template Engine ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 19:12 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVA Зная параметры заранее, можно составить оптимальный план получения значений параметров, минимизировав количество обращений по сети. Похоже на кейс для GraphQL. Но поскольку это достаточно новая штука, можно проще: Шаблон получает Map<String, String> - это параметры. Сначала пишем свою реализацию Map, которая сохраняет ключи, переданные в get(), и всегда возвращает пустую строку. Потом вызываем шаблон, передав ему эту Map. Результат работы шаблона выкидываем, но набор ключей, которые использовались в этом шаблоне, у нас теперь есть. Получаем значения для этих ключей и вызываем шаблон еще раз - теперь с настоящими данными. Этот подход можно расширить и на модель с вложенными объектами. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 19:23 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
UsmanLVAто не вытащить ужепри желании можно вытащить все . возможно, хотя и не уверен, что все. это как с рефлексией в FreeMarker. Надо снаружи описать (повторить в каком то смысле) то, что уже сделано внутри. Грамматика это, или тайное знание о названиях приватных классов и полей, которые можно достать рефлексией. При любом изменении версии это все может перестать работать. И все это надо покрывать тестами, а ведь сам шаблонизатор уже протестирован - хочется в это верить :) Поэтому, естественно, ищется шаблонизатор, который может эту простую задачу (для него, ведь он умеет парсить свои шаблоны!) решить "из коробки". Usmanкоторая не относится к теме Template Engine так я об этом и не говорю ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 19:27 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
scfПохоже на кейс для GraphQL. Но поскольку это достаточно новая штука, можно проще: Шаблон получает Map<String, String> - это параметры. Сначала пишем свою реализацию Map, которая сохраняет ключи, переданные в get(), и всегда возвращает пустую строку. Потом вызываем шаблон, передав ему эту Map. Результат работы шаблона выкидываем, но набор ключей, которые использовались в этом шаблоне, у нас теперь есть. Получаем значения для этих ключей и вызываем шаблон еще раз - теперь с настоящими данными. Этот подход можно расширить и на модель с вложенными объектами. так нельзя, потому что есть ветвления. а сразу по всем веткам пройтись нельзя ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 19:29 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVA, Если есть ветвление, то вы не можете заранее знать, какие данные нужны - для рендера левой ветки или для рендера правой ветки. Возможно, ваша задача не так уж формализуема? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 19:38 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
scf, я в первом посте говорил, что в случае ветвления берем из всех веток. однако, холостой пробег шаблонизатора может не попасть даже в одну единственную ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 20:23 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
LVA, тогда проще всего либо отпарсить шаблоны, либо выковырять из скомпилированного шаблона фримаркера нужные переменные. Рекурсивный нисходящий парсер руками - это куда проще, чем кажется. Смотреть тут: https://en.wikipedia.org/wiki/Recursive_descent_parser ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.08.2017, 20:49 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
scf, Но самое основное требование - движок должен уметь определить по шаблону (включая вложенные шаблоны) список переменных, которые нужны для формирования Data Model. Есть ветвление, то надо собрать переменные по всем веткам (то есть все, что есть в шаблоне). Уже посмотрел FreeMarker, Velocity, Mustache ... но, увы, ни один из них не позволяет получить список переменных на этапе разбора шаблона. Никакой шаблонизатор так не разбирает разметку, т.к. "правильные" ветвления ненужные кейсы просто игнорируют при парсинге (видел исключение - неправильные ветвления в кривоватых ранних сборках жсф ти ли 2.0, то ли 2.1 версии через атрибут rendered). Рецепт есть, я как-то дергал список переменных из xhtml (тот же самый жсф, но это применимо к чему угодно) через самописный скрипт на ноджс. Можно и на чем-то другом написать, но смысл в том, что эта задача должна решаться извне. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 26.08.2017, 12:37 |
|
||
|
Template engine
|
|||
|---|---|---|---|
|
#18+
mars478, Приходится как то извращаться именно "извне". Но делать такое извне как раз неправильно, т.к. завязываемся на специфику конкретного шаблонизатора, которая весьма нетривиальна. А именно, приходится учитывать области видимости переменных в шаблоне, включая переменные, объявленные во внутренних шаблонах. Например, мы можем объявить (через директиву #set) переменную X, и в этом же шаблоне есть ее использование в виде плэйсхолдера ${X}. Является ли X переменной шаблона ? Если она в области видимости объявленной директивы set, то не является, а если за ее пределами, то является. Можем также объявить переменную цикла X, которая живет только внутри цикла. А когда все это касается еще и вложенных шаблонов, то все еще больше усложняется. Например, шаблон T1 требует переменную A и делает импорт шаблона T2 Шаблон T2 требует только переменную B. Какие переменные понадобится передать в шаблонизатор, чтобы сформировать текст на основе шаблона T1 ? Вроде просто: A и B. Но нет. Возможно, B - это переменная цикла в шаблоне T1, или такая переменная объявлена директивой #set (тут еще важно, импорт сделан ДО объявления директивы или после). Есть и другие фишки, например, в pebble есть возможность сделать импорт шаблона, передав ему на вход какие то переменные дополнительно. В Mustache вообще переменную задают не абсолютным именем, а относительным: Код: java 1. 2. 3. дает несколько вариантов: автор - name - user.name - user[i].name Тут вообще дерево вариантов имен получается. Наверняка, есть и другие грабли, на которые я еще не наступил. Ну а в общем случае задача вообще нерешаема, т.к. имя вложенного шаблона в некоторых шаблонизаторах может вычисляться динамически, через плейсхолдеры, но если отбросить такой вариант, то шаблонизатор, безусловно мог бы решить такую задачу изнутри. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.08.2017, 15:02 |
|
||
|
|

start [/forum/topic.php?all=1&fid=59&tid=2122629]: |
0ms |
get settings: |
10ms |
get forum list: |
19ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
44ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
95ms |
get tp. blocked users: |
2ms |
| others: | 260ms |
| total: | 448ms |

| 0 / 0 |
