提示:不支持.doc文件的读取
有一个客户有这样的需求,须要在ThinkPHP里使用PHPWord组件,把一个文档(DOC1)的内容,插入另外一个文档(DOC2)的指定页内。因为两个文档的内容都不是固定的,因此不能使用PHPWord的Template功能。
之前历来没有使用过PHPWord,因此先后也折腾了几天。从熟悉PHPWord的功能开始,看示例代码,还有源码,最终仍是摸索出来解决方案,下面说下解决思路:php
首先读取DOC1的内容,PHPWord把内容分红不一样的节点和容器,最顶级的是Section,里面有TextRun(文本块),Table(表格)等容器。这些容器里又有Text(文本),Row(表格行),Cell(单元格)等,还有一些其余的TextBreak,PageBreak(分页符)等制表符。
逐级读取内容后,而后把读取出的内容插入到一个新的文档内。当读取到指定的分页符以后,再读取DOC2的内容,跟着前面的内容插入,最后保存新的文档。程序员
贴一部分代码:this
namespace Home\Logic; Vendor('PhpOffice.autoload'); use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\IOFactory; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Shared\ZipArchive; use PhpOffice\PhpWord\Settings; class MergeFile { private $currentPage = 0; // 当前分页 private $page = 0; // 插入页数 private $args = null; // 文本段样式 private $tmpFiles = []; // 临时文件 /** * 合并文件 * * @param URI * 文件1地址 * @param URI * 文件2地址 * @param Numeric * 指定插入的页数 * * @return String * 新文件的URI */ public function joinFile($file1, $file2, $page) { $S1 = IOFactory::load($file1)->getSections(); $S2 = IOFactory::load($file2)->getSections(); $this->page = $page > 0 ? $page - 1 : $page; $phpWord = new PhpWord(); foreach ($S1 as $S) { $section = $phpWord->addSection($S->getStyle()); $elements = $S->getElements(); # 逐级读取/写入节点 $this->copyElement($elements, $section, $S2); } $F1 = IOFactory::createWriter($phpWord); $path = $_SERVER['DOCUMENT_ROOT'] . __ROOT__ . '/Public/Write/'; if(!is_dir($path)) mkdir($path); $filePath = $path . time() . '.docx'; $F1->save($filePath); # 清除临时文件 foreach($this->tmpFiles as $P) { unlink($P); } return $filePath; } /** * 逐级读取/写入节点 * * @param Array * 须要读取的节点 * @param PhpOffice\PhpWord\Element\Section * 节点的容器 * @param Array * 文档2的全部节点 */ private function copyElement($elements, &$container, $S2 = null) { $inEls = []; foreach ($elements as $i => $E) { # 检查当前页数 if ($this->currentPage == $this->page && !is_null($S2)) { # 开始插入 foreach ($S2 as $k => $v) { $ELS = $v->getElements(); $this->copyElement($ELS, $container); } # 清空防止重复插入 $S2 = null; } $ns = get_class($E); $elName = end(explode('\\', $ns)); $fun = 'add' . $elName; # 统计页数 if ($elName == 'PageBreak') { $this->currentPage ++; } # 合并文本段 if($elName == 'TextRun' #&& !is_null($S2) ) { $tmpEls = $this->getTextElement($E); if(!is_null($tmpEls)) { $inEls = array_merge($inEls, $tmpEls); } $nextElName = ''; if($i + 1 < count($elements)) { $nextE = $elements[$i + 1]; $nextClass = get_class($nextE); $nextElName = end(explode('\\', $nextClass)); } if($nextElName == 'TextRun') { # 对比当前和下一个节点的样式 if(is_object(end($inEls))) { $currentStyle = end($inEls)->getFontStyle(); } else { continue; } $nextEls = $this->getTextElement($nextE); if(is_null($nextEls)) { $nextStyle = new Font(); } else { $nextStyle = current($nextEls)->getFontStyle(); } } } # 设置参数 $a = $b = $c = $d = $e = null; @list($a, $b, $c, $d, $e) = $args; $newEl = $container->$fun($a, $b, $c, $d, $e); $this->setAttr($elName, $newEl, $E); #$inEls = []; if(method_exists($E, 'getElements') && $elName != 'TextRun' ) { $inEls = $E->getElements(); } if(method_exists($E, 'getRows')) $inEls = $E->getRows(); if(method_exists($E, 'getCells')) $inEls = $E->getCells(); if (count($inEls) > 0) { $this->copyElement($inEls, $newEl); $inEls = []; $this->args = null; } } return $pageIndex; } /** * 获取Text节点 */ private function getTextElement($E) { $elements = $E->getElements(); $result = []; foreach($elements as $inE) { $ns = get_class($inE); $elName = end(explode('\\', $ns)); if($elName == 'Text') { $inE->setPhpWord(null); $result[] = $inE; } elseif (method_exists($inE, 'getElements')) { $inResult = $this->getTextElement($inE); } if(!is_null($inResult)) $result = array_merge($result, $inResult); } return count($result) > 0 ? $result : null; } private function setAttr($elName, &$newEl, $E) { switch (strtolower($elName)) { case 'footnote': $newEl->setReferenceId($E->getReferenceId()); break; case 'formfield': $newEl->setName($E->getName()); $newEl->setDefault($E->getDefault()); $newEl->setValue($E->getValue()); $newEl->setEntries($E->getEntries()); break; case 'object': $newEl->setImageRelationId($E->getImageRelationId()); $newEl->setObjectId($E->getObjectId()); break; case 'sdt': $newEl->setValue($E->getValue()); $newEl->setListItems($E->getListItems()); break; case 'table': $newEl->setWidth($E->getWidth()); break; } } }
程序员客栈,聚集各路码农,找到你的靠谱技术小伙伴 http://t.cn/RXz4ONTspa