【问题标题】:Error on variable with XML tags when parsing ODT files解析 ODT 文件时带有 XML 标记的变量出错
【发布时间】:2015-09-28 16:47:26
【问题描述】:

我正在一个需要处理 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>

如您所见,变量名称为&lt;/text:span&gt;tipoDocumento&lt;text:span text:style-name="T7"&gt;。该文档是在 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 错误:

&lt;b&gt;TinyButStrong Error&lt;/b&gt; in field &amp;#91;b.&lt;/text:span&gt;tipoDocumento&lt;text:span text:style-name...]: item '&amp;lt;/text:span&amp;gt;tipoDocumento&amp;lt;text:span text:style-name' is not an existing key in the array. &lt;em&gt;This message can be cancelled using parameter 'noerr'.&lt;/em&gt;

我做了一些调试,发现在核心 tbs_class.php 第 1177 行(在 meth_Locator_Replace() 中,这是引发错误的地方),$Loc-&gt;SubLst[$i] 的内容是 &lt;/text:span&gt;tipoDocumento&lt;text:span text:style-name,这并不'不匹配我的数组中的值。

所以,我假设由于某种原因,TBS 正在通过等号 (=) 爆炸索引,从而导致此问题。所以,

  1. 这是故意的吗?
  2. 能否修复此问题(以防出现错误)以允许带有等号的标签?
  3. 有没有更好的方法来避免变量中的标签,或者在 LibreOffice 中有没有办法避免这种情况?

【问题讨论】:

    标签: php odt opentbs tinybutstrong


    【解决方案1】:

    字符串&lt;/text:span&gt;tipoDocumento&lt;text:span text:style-name="T7"&gt;不能是TBS中的字段名。这是因为空格、等号、点和分号等是 TBS 字段的特殊字符。

    当您更改格式或有拼写信息时,可以将此类内部 XML 内容自动添加到 LibreOffice(甚至 Ms Office)中。

    解决方法是在LibreOffice中选中TBS字段,然后剪切,然后粘贴不格式化。那么所有内部 XML 应该都消失了,或者至少它只是限制文本而不剪切它。

    【讨论】:

    • 感谢您的回答以及您在 TBS / OpenTBS 中所做的所有工作 - 这是一堂很棒的课!上传模板文件时,我最终解析了模板的源以删除标签(检查我的own answer)。我的解决方案允许最终用户无需担心地编辑文档(尽管将来可能会出现一些意外行为)。
    【解决方案2】:

    @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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-18
      • 1970-01-01
      • 2015-09-18
      • 2017-08-05
      • 2020-11-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多