解析 ODT 文件时带有 XML 标签的变量出错
Error on variable with XML tags when parsing ODT files
我在需要处理 ODT 文档的系统中实施 TinyButStrong / OpenTBS,但我遇到了变量名称中包含标签的特定模板的问题。
情况如下:
模板部分:
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()
中,这是抛出错误的地方),[=18= 的内容] 是 </text:span>tipoDocumento<text:span text:style-name
,与我的数组中的值不匹配。
所以,我假设由于某种原因,TBS 正在用等号 (=) 展开索引,这导致了这个问题。所以,
- 这是故意的吗?
- 是否可以修复此问题(以防出现错误)以允许使用等号标记?
- 有没有更好的方法来避免变量中的标签,或者有没有办法在 LibreOffice 中避免这种情况?
字符串</text:span>tipoDocumento<text:span text:style-name="T7">
不能是TBS中的字段名。这是因为space、等号、点、分号等是TBS字段的特殊字符
这样的内部XML内容可以在您更改格式或有拼写信息时自动添加到LibreOffice(甚至Ms Office)中。
解决方法是selectLibreOffice中的TBS字段,然后剪切,然后不格式化粘贴。那么所有内部 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.
我在需要处理 ODT 文档的系统中实施 TinyButStrong / OpenTBS,但我遇到了变量名称中包含标签的特定模板的问题。
情况如下:
模板部分:
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()
中,这是抛出错误的地方),[=18= 的内容] 是 </text:span>tipoDocumento<text:span text:style-name
,与我的数组中的值不匹配。
所以,我假设由于某种原因,TBS 正在用等号 (=) 展开索引,这导致了这个问题。所以,
- 这是故意的吗?
- 是否可以修复此问题(以防出现错误)以允许使用等号标记?
- 有没有更好的方法来避免变量中的标签,或者有没有办法在 LibreOffice 中避免这种情况?
字符串</text:span>tipoDocumento<text:span text:style-name="T7">
不能是TBS中的字段名。这是因为space、等号、点、分号等是TBS字段的特殊字符
这样的内部XML内容可以在您更改格式或有拼写信息时自动添加到LibreOffice(甚至Ms Office)中。
解决方法是selectLibreOffice中的TBS字段,然后剪切,然后不格式化粘贴。那么所有内部 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.