用 PhpWord 中的格式替换文本中的 html 标签

Posted

技术标签:

【中文标题】用 PhpWord 中的格式替换文本中的 html 标签【英文标题】:Replace html tags in text with formatting in PhpWord 【发布时间】:2020-12-24 15:12:57 【问题描述】:

我有什么:

模板文档template.docx 内部带有标记 - $position_to_insert_text 变量$text_to_insert_in_template中的字符串,内部带有<strong> html标签-My <strong>example string</strong> with html tag.

我想要什么:

打开模板template.docx$position_to_insert_text 替换为$text_to_insert_in_template<strong></strong> 标记之间插入的文本必须采用强格式 - 我的示例字符串 带有 html 标记。

我的工作:

$text_to_insert_in_template = 'My <strong>example string</strong> with html tag.';
$template_path = 'templates/template.docx';

$templateProcessor = new \phpOffice\PhpWord\TemplateProcessor($template_path);
$templateProcessor->setValue('position_to_insert_text', $text_to_insert_in_template);
$templateProcessor->saveAs('result.docx');

结果

损坏的result.docx 文档无法打开它。原因 - 未处理 html 标签。如果htmlspecialchars($text_to_insert_in_template) 结果我可以打开result.docx 但html标签显示为纯文本。

我尝试将 html 标签替换为原生单词标签

$text_to_insert_in_template = 'My <strong>example string</strong> with html tag.';
$template_path = 'templates/template.docx';

$text_to_insert_in_template = str_replace('<strong>', "<w:b val='true'/>", $text_to_insert_in_template);
$text_to_insert_in_template = str_replace('</strong>', "<w:b val='false'/>", $text_to_insert_in_template);

$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor($template_path);
$templateProcessor->setValue('position_to_insert_text', $text_to_insert_in_template);
$templateProcessor->saveAs('result.docx');

结果我可以打开result.docx,但里面的文本也没有格式和html标签:

我怎样才能得到我想要的结果? - 我的 示例字符串 带有 html 标记。

【问题讨论】:

【参考方案1】:

我们手头有类似的任务。在寻找解决方案时,我发现了这个问题,并想将我们的解决方案作为示例。

一般的问题是,模板处理器(还)不支持使用 HTML 标记作为宏的值。根据您的 PhpWord 设置,甚至可以使用 setValue 方法对值进行转义。有缺陷的 WordProcessingML 可能会破坏您的文档。

但模板处理器允许用 PhpWord 元素替换包含宏的 &lt;w:p&gt; 段落 (setComplexBlock) 或 &lt;w:r&gt; 文本运行 (setComplexValue)。

而且 PhpWord 支持将 HTML 基本解析为容器元素,例如表格单元格或文本框。您可以使用它来将 HTML 标记添加到模板中。不幸的是,这也会添加容器元素。

我们不想拥有这个额外的包装器,并实现了两者的混合,使用包装器容器,但只打印其内容。

步骤如下:

创建一个自定义 TemplateProcessor 类,扩展 PhpWord 的通用 TemplateProcessor(在我们的示例中没有命名空间,但您可以根据自己的喜好添加合适的命名空间), 添加一个setHtmlBlockValue 方法,该方法 实例化一个容器元素(在我们的示例中为TextBox), 利用 Html 帮助类将 HTML 标记解析到其中, 然后使用Container编写器将容器内容渲染成符合Word2007的WordProcessingML, 最后但并非最不重要的一点是将包含宏的整个段落替换为呈现的内容。
<?php

use PhpOffice\PhpWord\Element\TextBox;
use PhpOffice\PhpWord\Shared\Html;
use PhpOffice\PhpWord\Shared\XMLWriter;
use PhpOffice\PhpWord\TemplateProcessor as PhpWordTemplateProcessor;
use PhpOffice\PhpWord\Writer\Word2007\Element\Container;

/**
 * Custom PhpWord template processor.
 *
 * Extends the generic template processor of PhpWord by means to
 * replace a macro with HTML markup content.
 */
class TemplateProcessor extends PhpWordTemplateProcessor 

    /**
     * Replaces a macro block with the given HTML markup.
     *
     * PhpWord's variables replacing doesn't allow to use HTML markup as
     * macro replacement content.
     *
     * This method is a workaround that uses the PhpWord Html service to
     * parse Html into PhpWord elements, adds them as children to a
     * container element (TextBox), then uses the Container writer to
     * write its children elements only.
     *
     * @param string $search
     *   The macro (variable) name.
     * @param string $markup
     *   The HTML markup as a string.
     */
    public function setHtmlBlockValue($search, $markup)
    
      // Create a dummy container element for the content.
      $wrapper = new TextBox();

      // Parse the given HTML markup and add it as child elements
      // to the container.
      Html::addHtml($wrapper, $markup);

      // Render the child elements of the container.
      $xmlWriter = new XMLWriter();
      $containerWriter = new Container($xmlWriter, $wrapper, false);
      $containerWriter->write();

      // Replace the macro parent block with the rendered contents.
      $this->replaceXmlBlock($search, $xmlWriter->getData(), 'w:p');
    


无需手动操作 HTML 即可使用它,并且支持与 PhpWords Html 助手支持的相同标记和属性:

$text_to_insert_in_template = 'My <strong>example string</strong> with html tag.';
$template_path = 'templates/template.docx';

$templateProcessor = new TemplateProcessor($template_path);
$templateProcessor->setHtmlBlockValue('position_to_insert_text', $text_to_insert_in_template);
$templateProcessor->saveAs('result.docx');

以上代码旨在作为灵感,并与使用 CKEditor 创建的经过净化的 HTML 标记一起使用。您可以根据需要对其进行更改(例如,使用表格单元格代替,替换文本运行而不是段落,...)。

【讨论】:

以上是关于用 PhpWord 中的格式替换文本中的 html 标签的主要内容,如果未能解决你的问题,请参考以下文章

Laravel引入phpoffice/phpword替换Word文件内容

Laravel引入phpoffice/phpword替换Word文件内容

PHPWordPHPOffice 套件之PHPWord快速入门

PHPWord使用PHPWord替换模板变量大段文字并换行设置字体字号

PHPWord使用PHPWord替换模板变量大段文字并换行设置字体字号

PhpWord 将图像添加到表格单元格