Html转Word

HTML转Word:自定义类实现富文本变量替换与印章添加

需求

将富文本编辑后的HTML代码片段转换为Word文件,替换Word文件模板变量,加盖章,生成并打包下载

摘要

在尝试使用PHPWord进行转换后,生成的Word文件没有样式,使用原生生成方式PHPWord则无法打开文件,因此转换思路如下

  1. 先将HTML代码块格式化为可导出的Word格式(视图、保留样式)
  2. 替换HTML内模板参数为变量
  3. 添加印章变量
  4. 打包zip下载(此处生成了多个文件所以多了一步打包zip)

工具类代码

<?php

namespace app\common\utils;

/**
 * 自定义 HTML与Word操作类处理
 * @author Teanxo
 */
class Html2Word
{
    private $html;

    private $htmlTagTemp = <<<HTML
<html xmlns:v='urn:schemas-microsoft-com:vml'xmlns:o='urn:schemas-microsoft-com:office:office'xmlns:w='urn:schemas-microsoft-com:office:word'xmlns:m='http://schemas.microsoft.com/office/2004/12/omml'xmlns='http://www.w3.org/TR/REC-html40'>
HTML;

    /**
     * html字符内 挂载到header标签内的模板
     * @var string
     */
    private $headerTmp = <<<HTML
<!--[if gte mso 9]><xml><w:WordDocument><w:View>Print</w:View><w:TrackMoves>false</w:TrackMoves><w:TrackFormatting/><w:ValidateAgainstSchemas/><w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid><w:IgnoreMixedContent>false</w:IgnoreMixedContent><w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText><w:DoNotPromoteQF/><w:LidThemeOther>EN-US</w:LidThemeOther><w:LidThemeAsian>ZH-CN</w:LidThemeAsian><w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript><w:Compatibility><w:BreakWrappedTables/><w:SnapToGridInCell/><w:WrapTextWithPunct/><w:UseAsianBreakRules/><w:DontGrowAutofit/><w:SplitPgBreakAndParaMark/><w:DontVertAlignCellWithSp/><w:DontBreakConstrainedForcedTables/><w:DontVertAlignInTxbx/><w:Word11KerningPairs/><w:CachedColBalance/><w:UseFELayout/></w:Compatibility><w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel><m:mathPr><m:mathFont m:val='Cambria Math'/><m:brkBin m:val='before'/><m:brkBinSub m:val='--'/><m:smallFrac m:val='off'/><m:dispDef/><m:lMargin m:val='0'/> <m:rMargin m:val='0'/><m:defJc m:val='centerGroup'/><m:wrapIndent m:val='1440'/><m:intLim m:val='subSup'/><m:naryLim m:val='undOvr'/></m:mathPr></w:WordDocument></xml><![endif]-->
HTML;

    /**
     * 当有一些不是成员变量的时候
     * 需要指定一个对象 才可对特殊变量进行高级赋值操作
     * 代替适配器,使用动态调用方式
     * $operationInstance->$func($sourceData)
     * @var null
     */
    private $operationInstance = null;


    /**
     * 将一个HTML字符串格式为可导出Word的数据
     */
    public function replaceHTML()
    {
        // 判断字符串中是否存在HTML标签
        $htmlIndex = strpos($this->html, "<html");


        if ($htmlIndex !== false) {
            $htmlEndIndex = stripos($this->html, ">");
            // 删除HTML开始头部标签
            $endHtml = substr($this->html, $htmlEndIndex + 1);
            $this->html = $this->htmlTagTemp . $endHtml;
        } else {
            $this->html = $this->htmlTagTemp . $this->html . "</html>";
        }


        // 判断字符串中是否存在header标签
        $headerIndex = stripos($this->html, "<head>");
        $hRepIndex = stripos($this->html, "<!--[if gte mso 9]>");

        // header标签 且定义插入标签不存在时候执行
        if ($headerIndex !== false && $hRepIndex === false) {
            // 拿到meta标签开始位置
            $startIndex = stripos($this->html, "<meta");

            // 必须匹配到meta结束标签才能执行
            preg_match_all('/<meta(.*)$/m', $this->html, $matches);
            if (count($matches) > 0) {

                // 拿到head结束标签位置
                $lastMetaStr = end($matches[0]);
                $lastIndex = strpos($this->html, $lastMetaStr);
                $endIndex = $lastIndex + strlen($lastMetaStr);

                // 为header插入word导出所需标签
                $startHtmlStr = substr($this->html, 0, $lastIndex);
                $endHhtmlStr = substr($this->html, $endIndex);

                // 为head拼接指定标签
                $this->html = $startHtmlStr . $this->headerTmp . $endHhtmlStr;

            }

        } else if ($headerIndex === false) {
            // header标签不存在 那么创建

            // 拿到meta标签开始位置
            $startIndex = stripos($this->html, "<meta");
            // 拿到meta标签结束位置
            preg_match_all('/<meta(.*)$/m', $this->html, $matches);
            if (count($matches) > 0) {
                // 拿到head结束标签位置
                $lastMetaStr = end($matches[0]);
                $lastIndex = strpos($this->html, $lastMetaStr);
                $endIndex = $lastIndex + strlen($lastMetaStr);

                $startHtmlStr = substr($this->html, 0, $lastIndex);
                $endHhtmlStr = substr($this->html, $endIndex);

                // 为head拼接指定标签
                $this->html = $startHtmlStr . "<head>" . $this->headerTmp . "</head>" . $endHhtmlStr;


            }
        }
        return $this;
    }

    /**
     * 将模板化的HTML变量  替换
     * @param array $tmpVar 示例 ['模板名称 例如:项目名称'=>'字段名称']
     * @param array $sourceData 示例 ['字段名称'=>'字段值']
     * @return $this
     */
    public function variables(array $tmpVar, array $sourceData)
    {
        foreach ($tmpVar as $key => $value) {
            if (is_string($value) && isset($sourceData[$value])) {
                $this->variable('$(' . $key . ')', $sourceData[$value]);
            } else if (is_array($value) && key_exists("func", $value)) {
                $func = $value['func'];
                $this->html = str_replace('$(' . $key . ')', $this->operationInstance->$func($sourceData), $this->html);
            }
        }
        return $this;
    }

    /**
     * 单个模板变量赋值
     * @param string $tmpName
     * @param $val
     */
    public function variable(string $tmpName, $val)
    {
        $this->html = str_replace($tmpName, $val, $this->html);
        return $this;
    }

    /**
     * 将变量以正则表达式形式进行赋值
     * @param $pattern
     * @param $val
     */
    public function pregMatchVariable($pattern, $val)
    {
        $this->html = preg_replace($pattern, $val, $this->html);
        return $this;
    }


    /**
     * 写入Word文件
     * @param string $fileName 文件路径
     * @return void
     */
    public function writeWord(string $fileName)
    {
        $writefile = fopen($fileName, 'wb') or die("创建文件失败"); //wb以二进制写入
        fwrite($writefile, $this->html);
        fclose($writefile);
        file_put_contents($fileName, $this->html);
    }

    /**
     * 挂载HTML数据
     * @param mixed $html
     */
    public function setHtml(string $html)
    {
        $this->html = $html;
        return $this;
    }

    /**
     * 获取HTML数据
     * @return string
     */
    public function getHtml()
    {
        return $this->html;
    }

    /**
     * @param  $operationInstance
     */
    public function setOperationInstance($operationInstance)
    {
        $this->operationInstance = new $operationInstance();
        return $this;
    }


}

使用方法

$html2Word = new Html2Word();

// 一些示例数据
$configs = array(
	'项目名称' => 'product_name',
	'项目别名' => 'product_as',
	// 当此处设置为 array时 且存在func属性,那么会执行 Html2WordOperation类中的seal方法,也就是setOperationInstance时传入的类
	'盖章' => [
		'func' => 'seal'
	]
);


$variableData = array(
	'product_name' => '小米手机',
	'product_as' => '小米'
);

$html2Word->setOperationInstance(Html2WordOperation::class) // 传入自定义操作类
          ->setHtml($productTemplateinfo['content']) // 挂载HTML代码片段
          ->replaceHTML() // 整理为可导出Word格式
          ->variables($configs, $variableData) // 将HTML代码模板的变量转为实际参数
          ->pregMatchVariable('/人民币【.*万元整+/', $amountText) // 正则表达式变量赋值
          ->writeWord($filePath) // 导出文件;

Html2WordOperation类示例
/**
 * 对转换中变量进行特殊方法处理
 */
class Html2WordOperation
{
    /**
     * 生成盖章
     * @param $sourceData 同等variableData
     * @return string
     */
    public function seal($sourceData)
    {
        $seal = $sourceData['seal'];
        // 读取盖章数据
        return <<<HTML
<img src="$seal" style="width: 100px;height: 100px;margin-top: 15px;" />
HTML;

    }
}
<think>首先,用户的问题是基于系统指令和提供的引用内容:"我想查找将HTML换为Word的方法"。我需要参考用户上一次的问题和我的回答,但在这个上下文里,用户上一次的问题就是这个,所以我应该直接回答这个查询。 系统指令包括: - 所有行内数学表达式使用 $...$ 格式。 - 独立公式使用 $$...$$ 格式。 - LaTeX 语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,例如 [^1]。 提供的引用有四个: - [^1]: 关于 PHP 实现 HTML Word 的方法,包括使用 composer 包和 base64 图片。 - [^2]: Vue 实现 HTML Word,涉及生成 Word 文档和上传。 - [^3]: Java 和 PHP 中的方法,提到 Python 中方法少,以及处理异步数据和图片的问题。 - [^4]: Java 实现 HTML Word 的依赖排除示例。 用户的问题是关于 HTML Word 的方法,所以我需要综合这些引用来提供信息。 回答结构需要清晰,帮助用户逐步解决问题。我应该: 1. **介绍主题**:简要解释 HTML Word 是什么。 2. **提供方法**:基于引用,总结不同语言的实现方法。 - 特别是 PHP、Java、Vue(JavaScript)的方法。 3. **关键点**:强调如何处理图片和异步数据,因为引用[^3]提到这是难点。 4. **添加引用标识**:在引用内容后自然地添加 [^n]。 5. **生成相关问题**:在回答的最后,添加相关问题部分,如示例中的 "§§相关问题§§"。 步骤: - **PHP 方法**:从引用[^1],使用 composer require cshaptx4869/html2word,或将图片为 base64。 - **Vue/JavaScript 方法**:从引用[^2],在 Vue 中生成 Word 文档,可能涉及特定库或方法。 - **Java 方法**:从引用[^3]和[^4],使用 Jacob、Apache POI、Freemarker 等;排除某些依赖。 - **通用挑战**:处理图片和异步数据(引用[^3])。 由于引用来自不同来源,我需要整合成一个连贯的回答。用户指定了“参考站内引用”,所以我应该主要基于这些引用。 回答大纲: 1. **开头**:解释 HTML Word 的需求和方法概述。 2. **具体方法**: - PHP:使用 composer 包或写入 Word 文件。 - Java:使用库如 Apache POI。 - Vue/JavaScript:在客户端生成 Word。 - 强调图片处理(base64)。 3. **注意事项**:处理异步数据等挑战。 4. **引用标识**:在对应部分添加。 5. **相关问题**:生成几个相关问题。 生成相关问题: - 类似示例:"§§相关问题§§",然后列出几点。 - 例子:1. 如何处理图片换? 2. 在 Python 中如何实现?等等。 确保语言是中文。 最终输出格式: - 回答内容。 - 相关问题部分。 </think>### HTML Word 的方法 将 HTML 内容换为 Word 文档是一项常见需求,尤其在 Web 应用中导出报告或文档时。方法因编程语言和场景而异,主要涉及处理 HTML 结构、样式和嵌入图片的换。以下基于提供的引用内容,我为您总结了几种主流实现方法(PHP、Java、Vue/JavaScript),并强调关键点如图片处理和异步数据挑战。回答结构清晰,从原理到具体实现逐步展开。 #### 1. **PHP 实现方法** PHP 中可以通过两种方式将 HTML 换为 Word 文档: - **使用 Composer 包**:安装专用库如 `cshaptx4869/html2word`,通过命令行快速生成 Word 文件。代码简洁,适合简单场景: ```php composer require cshaptx4869/html2word // 示例代码:调用包的方法HTML $converter = new HtmlToWordConverter(); $converter->convert('input.html', 'output.docx'); ``` 这种方式自动处理基本 HTML 标签和样式[^1]。 - **直接写入 Word 并处理图片**:将 HTML 文件内容直接写入 Word 文档(.docx),同时将图片换为 base64 格式嵌入。这避免了外部依赖,但需手动处理图片编码: ```php $htmlContent = file_get_contents('input.html'); $base64Image = base64_encode(file_get_contents('image.png')); // 图片 base64 $wordContent = "<html><body>{$htmlContent}<img src='data:image/png;base64,{$base64Image}'/></body></html>"; file_put_contents('output.docx', $wordContent); ``` 这种方法灵活,但需注意 Word 对 base64 图片的支持限制[^1]。 #### 2. **Java 实现方法** Java 有多个成熟库可用于 HTML Word,支持复杂文档处理: - **使用 Apache POI 或 Jacob**:Apache POI 是常用库,能直接操作 Word 文档。Jacob 则通过 COM 接口实现,适合 Windows 环境。关键步骤包括读取 HTML 内容并写入 Word: ```java // 示例代码:使用 Apache POI 换 import org.apache.poi.xwpf.usermodel.XWPFDocument; String html = "<p>Hello, World!</p>"; XWPFDocument doc = new XWPFDocument(); doc.createParagraph().createRun().setText(html); // 简化示例,实际需解析 HTML FileOutputStream out = new FileOutputStream("output.docx"); doc.write(out); out.close(); ``` 在依赖管理中,需排除潜在冲突(如引用[^4]提到的 POI 排除)。 - **使用模板引擎如 Freemarker**:结合模板动态填充数据,尤其适合批量生成文档: ```java // 示例代码:Freemarker 配置 Configuration cfg = new Configuration(Configuration.VERSION_2_3_31); cfg.setTemplateLoader(new FileTemplateLoader(new File("templates"))); Template template = cfg.getTemplate("template.ftl"); Map<String, Object> data = new HashMap<>(); data.put("content", "<p>HTML Content</p>"); try (Writer out = new FileWriter("output.docx")) { template.process(data, out); } ``` 这种方式处理异步数据(如 AJAX 填充)时较复杂,需预加载所有内容[^3]。 #### 3. **Vue/JavaScript 实现方法** 在 Vue.js 等前端框架中,HTML Word 通常在客户端生成文件并上传后台: - **生成并导出 Word 文档**:用户通过拖拽组件生成 HTML 界面后,使用 JavaScript 库(如 html-docx-js)将 DOM 内容换为 .docx: ```javascript // 示例代码:Vue 中导出 Word import htmlToDocx from 'html-docx-js'; export default { methods: { exportToWord() { const htmlContent = document.getElementById('preview').innerHTML; // 获取预览区域的 HTML const docx = htmlToDocx.asBlob(htmlContent); // 换为 Word Blob // 后台上传(不触发用户下载) const formData = new FormData(); formData.append('file', docx, 'document.docx'); axios.post('/upload', formData); } } } ``` 这结合了实时预览和静默上传,优化用户体验[^2]。 #### 关键注意事项 - **图片处理**:HTML 中的图片常需为 base64 格式嵌入 Word(如引用[^1]和[^3]所述),否则可能丢失。Word 对 base64 支持有限,建议测试目标平台兼容性。 - **异步数据挑战**:如果 HTML 内容依赖 JavaScript 异步加载(如 API 数据),需在换前确保数据完全加载,否则导出可能不完整。这在 Python 等方法中更棘手[^3]。 - **跨语言比较**:Python 中工具较少,Java 和 PHP 方案成熟;Vue 方法适合前端集成,但依赖浏览器能力。 综上,选择方法时应考虑语言环境(如 PHP 快捷、Java 强大、Vue 前端友好)和项目需求。如果您提供具体场景(如语言或图片复杂度),我可进一步细化方案。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞鱼三两只

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值