Perl Template Toolkit - Preprocess шаблоны обратно в скрипт Perl
Простите, если этот вопрос уже был задан и / или дан ответ в другом месте.
Прежде чем я начну, я должен указать, что природа этого запроса может не требовать добавления кода в эту ветку, скорее ответом может быть просто ссылка на документацию модуля Template Toolkit с комментарием "ПРОЧИТАЙТЕ ЭТО СНОВА":). Чтобы быть еще более ясным, я согласился бы на краткий ответ ДА или НЕТ.
Допустим, у меня есть работающий Perl-скрипт, который обрабатывает шаблоны Template::Toolkit без проблем.
Но один из моих шаблонов содержит "имена" (имена людей, имена серверов, в конце концов это действительно не имеет значения: только "имена"). Эти имена используются для создания FILENAMES, содержащих обработанные данные позже.
Сегодня у меня это работает через следующий псевдокод:
$template->process('names.tt','output.txt');
Затем я беру сгенерированный список "имен" в "output.txt" и помещаю их в массив в том же исполняемом скрипте Perl. Этот список затем используется итеративным способом для вывода данных, указанных в другом шаблоне, и присваивает имя каждому результирующему файлу на основе исходного "имени":
foreach(@names){
my $filename = $_ . '.txt';
$template->process('profile_doc.tt',$filename)
}
Как я уже сказал, все это прекрасно работает (на самом деле идеально). Моя проблема в том, что он наполняет мой код без необходимости (нужно управлять открытыми FH и т. Д.). Должен быть лучший путь, учитывая необычайные способности ТТ.
Поэтому я начал читать о включенных модулях Template::Toolkit (например, STASH, PROVIDER и т. Д.). Я понимаю, что STASH, например, позволяет вам вводить данные в существующий объект модуля шаблона дополнительным способом, однако это является противоположностью того, что я хочу сделать.
Мой фактический вопрос (опять же, ДА или НЕТ, было бы просто замечательно как ответы с точки зрения того, возможно ли это):
Возможно ли для сценария Perl прочитать шаблон, скажем, такой, который содержит объект HASH, хранящийся в Template-Toolkit, и создать новый HASH, который будет использоваться фактическим сценарием Perl (например, вне шаблона)?
Если бы это было возможно, это исключило бы необходимость извлечения данных в запутанном виде из одного шаблона и использования этих данных для обработки другого шаблона. Скорее я теоретически мог бы сделать следующее без необходимости вручную заполнять список, который нужно записать на диск, а затем снова прочитать через FH.
foreach(sort keys $derivedhash{obj}){
$filename = $_->{name} . '.txt';
$template->process('profile_doc.tt',$_->{name});
}
Спасибо, пожалуйста, поймите, что я приложил все усилия, чтобы создать пригодную для использования псевдомодель, поскольку реальный код включает в себя конфиденциальные элементы и, к сожалению, исключает раскрытие. Я надеюсь, вы поймете. Я могу предоставить другие "очищенные абстракции / примеры" по мере необходимости.
ОБНОВИТЬ
В ответ на пользователя икегами:
Во-первых, спасибо за ответ.
Хорошо, давайте начнем с одного из ваших комментариев: " ... который не имеет смысла, так как TT не хранит хэши"... Хм.... Если мы не говорим о двух разных вещах, это неправильно, как я делаю это сегодня.. например, вот размещенный в шаблоне объект, который содержит элементы начального хэша, о которых я говорил:
[%- SERVERS = [
{entry={
NAME => 'Server1'
SERIAL => '1234567890'
DESC => 'A file server'
}}
{entry={
NAME => 'Server2'
SERIAL => '0987654321'
DESC => 'An account server'
}}
]-%]
Еще раз, вышеупомянутое работает, и оно существует в TT..........., и, если я не ошибаюсь, вышесказанное, безусловно, выглядит, чувствует и чувствует себя как хэш.... Я даю вам, тем не менее, то, что он заключен в массив... так что, возможно, это не 100% -ный "чистый объект HASH" класса A, но я, конечно, действительно использую его как хэш (и, что очень приятно, тоже).
Прежде чем вы что-то скажете, я уже понимаю, что мне, скорее всего, потребуется обновить имена ключей, чтобы они были УНИКАЛЬНЫМИ для простоты анализа (сами по себе ключи хеш-функции должны быть уникальными), но это отдельная попытка.
Вы были правы, когда сказали: "Это явно не то, что вы хотели спросить". Позвольте мне прояснить окончательный вопрос, как вы и просили:
Может ли Template Toolkit из исполняемого сценария Perl прочитать "Шаблон 1", который содержит один объект HASH (как описано выше), и прочитать упомянутую структуру HASH в новый хеш-объект, который существует только внутри указанного исполняющего скрипта (в отличие от сам шаблон)? Этот "новый хеш" в конечном итоге будет использоваться для имен файлов, сгенерированных "шаблоном 2".
Наконец, чтобы удовлетворить ваш последний запрос:
Выше приведен отрывок ввода, который вы запрашивали. Вывод, который мне нужен, будет настоящим Perl-хешем, полученным из данных внутри вызываемого шаблона.
Так что в качестве эквивалента Perl (желаемый выход):
%newhash = (
entry => {
NAME => "Server1",
SERIAL => "1234567890",
DESC => "A file server"
},
.... other entries ....
);
.... будет использоваться для "подачи" определенных значений, скажем, значений "NAME", в другие шаблоны, обработанные "позже".
Надеюсь это прояснит путаницу... еще раз спасибо икегами...
2 ответа
Ради того, чтобы принять решение, я подумал, что покажу код, который использует JSON
модуль для загрузки некоторых данных из файла на диске
Предположим, мой файл data.json
содержит это (взято из ваших собственных данных образца)
servers.json
[
{
"NAME" : "Server1",
"SERIAL" : "1234567890",
"DESC" : "A file server"
},
{
"NAME" : "Server2",
"SERIAL" : "0987654321",
"DESC" : "An account server"
}
]
Затем я могу написать этот код Perl, чтобы открыть и прочитать данные в массив хэшей Perl, например так:
servers.pl
use strict;
use warnings 'all';
use v5.10.1;
use autodie;
use JSON;
use constant JSON_FILE => 'servers.json';
my $servers = do {
open my $fh, '<:raw', JSON_FILE;
local $/;
decode_json <$fh>;
};
use Data::Dump;
dd $servers;
выход
[
{ DESC => "A file server", NAME => "Server1", SERIAL => 1234567890 },
{ DESC => "An account server", NAME => "Server2", SERIAL => "0987654321" },
]
Обратите внимание, что я использовал autodie
прагма, чтобы избежать необходимости вручную проверять статус open
вызов. autodie
Впервые был сделан основной модуль в Perl версии 5.10.1, поэтому я тоже этого потребовал
decode_json
Вызов принимает только строку в формате JSON, поэтому я использовал do
блок, чтобы открыть и прочитать файл и декодировать содержимое, отбрасывая все временные значения, такие как дескриптор файла и строку JSON
Data::Dump
это только для того, чтобы показать форму структуры данных, прочитанной в
Данные JavaScript (JSON) очень похожи на эквивалентный Perl, за исключением следующего
- в Perl
=>
заменяется на:
- Допускаются только двойные кавычки, без одинарных кавычек
- Хеш-ключи, а также строковые значения должны быть заключены в кавычки
- Последний элемент списка может не иметь запятой
Но нет необходимости помещать кавычки вокруг числового литерального значения. Он работает так же, как Perl, так что, если вы хотите сохранить числовую строку с начальным нулем, вам нужно будет использовать кавычки, в противном случае пустое число хорошо
Я верю, что обратный процесс - написание файла JSON - очевиден. Ссылка на структуру данных Perl должна быть передана encode_json
создать строку JSON, которая затем записывается в файл обычным способом
Если вы отчаянно нуждаетесь в большей скорости кодирования и декодирования, тогда есть JSON::XS
модуль, который частично написан на C и, следовательно, гораздо быстрее, однако любой JSON-модуль будет работать намного быстрее, чем все, что вы могли бы установить с помощью Template Toolkit. Вариант XS представляет собой замену чистой версии Perl в отношении encode_json
а также decode_json
ТТ производит текст. Но если бы TT генерировал текстовое представление хеша, было бы легко создать хеш из него.
Шаблон:
[%- USE Template.Plugin.JSON -%]
[%- SERVERS = [ ... ] -%]
[%- SERVERS.json -%]
Код:
use JSON qw( from_json );
$template->process('template.tt', {}, \my $json)
or die(...);
my $servers = from_json($json);
Я использовал JSON, но подойдут и любые другие способы сериализации и десериализации структуры данных.
Тем не менее, я совершенно не понимаю, почему вы хотите это сделать. Вы даже не можете воспользоваться преимуществами функций TT таким образом!
Если бы смысл был в том, чтобы использовать возможности TT для изменения структуры данных, то создание самого шаблона JSON имело бы гораздо больше смысла. Например,
[
[% IF devel %]
{
"entry": {
"NAME": "Server1-devel",
"SERIAL": "1234567890",
"DESC": "Development server"
}
},
[% ELSE %]
{
"entry": {
"NAME": "Server1-prod",
"SERIAL": "1234567891",
"DESC": "Production server"
}
},
[% END %]
...
]
use JSON qw( from_json );
my %vars = (
devel => ...,
);
$template->process('template.tt', \%vars, \my $json)
or die(...);
my $servers = from_json($json);
Кстати, если у вас есть хеш с одним постоянным ключом, вы делаете что-то не так.
[
{ entry => { NAME => "Server1", SERIAL => 1234567890, DESC => "A file server" } },
{ entry => { NAME => "Server2", SERIAL => "0987654321", DESC => "An account server" } },
]
должно быть
[
{ NAME => "Server1", SERIAL => 1234567890, DESC => "A file server" },
{ NAME => "Server2", SERIAL => "0987654321", DESC => "An account server" },
]
или же
{
"Server1" => { SERIAL => 1234567890, DESC => "A file server" },
"Server2" => { SERIAL => "0987654321", DESC => "An account server" },
}