Я внедряю TinyButStrong / OpenTBS в системе, которая должна обрабатывать документы ODT, и столкнулся с проблемой, связанной с конкретным шаблоном, в котором есть теги внутри имени переменной.
Ситуация выглядит следующим образом:
Часть шаблона:
Соответствующая часть content.xml
<table:table-cell table:style-name="Table3.A1" office:value-type="string">
<text:p text:style-name="P22">Tipo de documento</text:p>
<text:p text:style-name="P29">
<text:span text:style-name="T7">
[b.</text:span>tipoDocumento<text:span text:style-name="T7">]
</text:span>
</text:p>
</table:table-cell>
Как видите, имя переменной </text:span>tipoDocumento<text:span text:style-name="T7">
, Документ был отредактирован в LibreOffice, и по неизвестной причине теги были добавлены.
Я думал, что смогу передать полное имя переменной (с включенными тегами), и OpenTBS правильно проанализирует значение, поэтому я попробовал следующее:
$data = ['</text:span>tipoDocumento<text:span text:style-name="T7">' => 'somevalue'];
$tbs = new clsTinyButStrong;
$tbs->Plugin(TBS_INSTALL, OPENTBS_PLUGIN);
$tbs->LoadTemplate($templatePath, OPENTBS_ALREADY_UTF8);
// Note that we need to send an array of arrays to $data,
$tbs->MergeBlock($block, 'array', [$data]);
Но это приводит к ошибке TBS:
<b>TinyButStrong Error</b> in field [b.</text:span>tipoDocumento<text:span text:style-name...]: item '</text:span>tipoDocumento<text:span text:style-name' is not an existing key in the array. <em>This message can be cancelled using parameter 'noerr'.</em>
Я сделал некоторые отладки и понял, что в основе tbs_class.php
строка 1177 (в meth_Locator_Replace()
, где выдается ошибка), содержание $Loc->SubLst[$i]
является </text:span>tipoDocumento<text:span text:style-name
, который не соответствует значению в моем массиве.
Итак, я предполагаю, что по какой-то причине TBS разрывает индекс знаком равенства (=), что вызывает эту проблему. Так,
Строка </text:span>tipoDocumento<text:span text:style-name="T7">
не может быть именем поля в TBS. Это потому, что пробел, символ равенства, точка и точка с запятой и некоторые другие являются специальными символами для полей TBS.
Такое внутреннее содержимое XML может быть автоматически добавлено в LibreOffice (или даже в Ms Office), когда вы изменили форматирование или когда есть информация об орфографии.
Решение состоит в том, чтобы выбрать поле TBS в LibreOffice, затем вырезать его, а затем паста без форматирования. Тогда весь внутренний XML должен был исчезнуть, или, по крайней мере, он ограничивает текст, не разрезая его.
@ Skrol29ответ является наиболее надежным решением.
Однако одна из причин, по которой мы используем шаблоны, заключается в том, что конечные пользователи могут их редактировать, и им будет нелегко объяснить, зачем им это нужно, поскольку в LibreOffice (или в Microsoft Office нет визуальных изменений). в этом отношении).
Итак, я закончил синтаксический анализ источника шаблона перед его сохранением, тем самым удалив все теги XML из переменных.
Это код, который я использую при загрузке нового файла шаблона:
// Create a temporary file, only to load it with TBS
// $fileContents is the binary file contents and $extensao is the file extension
$filePath = intranet_storage_path(sha1($fileContents) . '.' . $extensao, 'tmp');
// Store the binary contents in the file path
file_put_contents($filePath, $fileContents);
// Create a new TBS instance and load OpenTBS
$tbs = new clsTinyButStrong;
$tbs->Plugin(TBS_INSTALL, OPENTBS_PLUGIN);
// Load the temporary file
$tbs->LoadTemplate($filePath, OPENTBS_ALREADY_UTF8);
// Find all variables (the only block name is 'b')
preg_match_all(
"/(\[b\. # Start by finding a part of [ followed by the block name and a dot
[^.\];]+ # Now we should get all characters until one of the following is found: `.` (dot), `]`, `;
[\]|;] # Stop the regex when a `]` or `;` is found.
)/ix",
$tbs->Source,
$matches
);
// Loop through all the found variables
$searched = $replaced = [];
foreach ($matches[0] as $var) {
// Fill the $searched and $replaced where $searched is the real variable name
// with XML tags (if they exist) and $replaced is the variable without tags
$searched[] = $var;
$replaced[] = strip_tags($var);
}
// Replace the contents of the Source
$tbs->Source = str_replace($searched, $replaced, $tbs->Source);
// Store the final template file with variables without XML
$tbs->Show(OPENTBS_FILE, $filePath);
Я должен заявить, что это решение приведет к неверному XML, если в переменной есть только открытый или закрытый тег. Следующие примеры нарушат XML (и вы не сможете открыть или проанализировать документ):
<text:span text:style-name="T7">[b.tipoDocumento<text:span text:style-name="T7">]</text:span>
// OR
<text:span text:style-name="T7">[b.</text:span>tipoDocumento]</text:span>
Однако из тестовых случаев, которые у меня были, всегда есть открывающий и закрывающий тег (как представлено в вопросе), поэтому удаление их приведет к правильному XML.