当前位置: 首页 > news >正文

Word XML 批注范围克隆处理器

该类用于处理 Word 文档(XML 结构)中被批注标记的文本范围,
实现指定内容的深度克隆,并将其插入到目标节点之后。
适用于在生成或修改 .docx 文件时复制批注内容块。

/*** Word XML 批注范围克隆处理器* * 该类用于处理 Word 文档(XML 结构)中被批注标记的文本范围,* 实现指定内容的深度克隆,并将其插入到目标节点之后。* 适用于在生成或修改 .docx 文件时复制批注内容块。*/
class WordCommentRangeCloner
{/*** 存储文档节点的线性列表,用于通过索引快速访问* @var array*/private $domList = [];/*** 记录每个节点索引关联的命名信息,用于模板或块引用* 格式: [index] => [['type', 'name'], ...]* @var array*/private $domIdxToName = [];/*** 存储按名称组织的块引用,支持多实例* 格式: ['blockName#1'] => ['type' => [index1, index2, ...]]* @var array*/private $blocks = [];/*** 扩展索引映射,用于记录节点间的附加关联关系* 格式: [index] => [relatedIndex1, relatedIndex2, ...]* @var array*/private $idxExtendIdxs = [];/*** 将克隆的节点插入到目标节点之后** 如果目标节点有下一个兄弟节点,则插入到其前;* 否则作为父节点的最后一个子节点追加。** @param \DOMNode $copy 要插入的已克隆节点* @param \DOMNode $targetNode 目标位置的参考节点* @return void*/public function insertAfter($copy, $targetNode){if ($nextSibling = $targetNode->nextSibling) {// 如果存在下一个兄弟节点,则插入到它前面if ($parentNode = $nextSibling->parentNode) {$parentNode->insertBefore($copy, $nextSibling);}} else {// 否则作为父节点的最后一个子节点添加if ($parentNode = $targetNode->parentNode) {$parentNode->appendChild($copy);}}}/*** 克隆指定索引的节点及其子树,并插入到指定位置后** 此方法用于复制 Word 文档中被批注包裹的内容块。* 支持维护索引、命名、关联等元数据一致性。** @param int $nodeIdx 要克隆的原始节点在 domList 中的索引* @param int $endNodeIdx 插入位置的参考节点索引(插入到该节点之后)* @param string $name 原始块名称(用于命名新实例)* @param int $idx 克隆实例编号(用于区分多个副本,如 #1, #2)* @param int $reIdx 递归层级编号(嵌套克隆时使用)* @return int 返回克隆子树在 domList 中的起始索引*/private function cloneNode($nodeIdx, $endNodeIdx, $name, $idx, $reIdx = 0){$originalNode = $this->domList[$nodeIdx];$clonedNode = clone $originalNode;// 为克隆节点重建树索引(使用引用传递维护连续索引)$startIndex = count($this->domList);$this->treeToList($clonedNode, $startIndex);// 构建原始索引到新索引的映射表$oldToNewMap = $this->buildIndexMap($originalNode, $clonedNode);// 更新命名映射关系(domIdxToName 和 blocks)$this->updateNameMappings($originalNode, $oldToNewMap, $idx);// 更新扩展索引关联关系$this->updateExtendIdxs($originalNode, $oldToNewMap);// 将克隆的节点插入到目标节点之后$this->insertAfter($clonedNode, $this->domList[$endNodeIdx]);return $startIndex;}/*** 遍历节点树并生成线性节点列表,同时设置每个节点的起止索引** 用于重建克隆节点或新插入节点的索引结构。** @param \DOMNode $node 当前处理的节点* @param int|null $index 引用传递的当前索引值* @return void*/protected function treeToList($node, &$index = null){if ($index === null) {$index = count($this->domList);}if (is_null($node)) {return;}$node->idxBegin = $index;$node->tagList = [];$this->domList[$index++] = $node;if ($node->hasChildNodes()) {foreach ($node->childNodes as $childNode) {if ($childNode->nodeType !== XML_TEXT_NODE) { // 非文本节点$tagName = $childNode->tagName;$node->tagList[$tagName][] = $childNode;$this->treeToList($childNode, $index);// 合并后代标签列表foreach ($childNode->tagList as $tag => $nodes) {foreach ($nodes as $n) {$node->tagList[$tag][] = $n;}}}}}$node->idxEnd = $index - 1;}/*** 构建原始节点索引到克隆节点索引的映射表** @param \DOMNode $orig 原始节点* @param \DOMNode $clone 克隆节点* @return array 映射表 [oldIndex => newIndex]*/private function buildIndexMap($orig, $clone){$map = [];$this->walkNodeAndMap($orig, $clone, $map);return $map;}/*** 递归遍历原始与克隆节点,建立索引映射** @param \DOMNode $orig* @param \DOMNode $clone* @param array &$map 引用传递的映射表* @return void*/private function walkNodeAndMap($orig, $clone, &$map){$map[$orig->idxBegin] = $clone->idxBegin;if ($orig->hasChildNodes()) {$origChildren = iterator_to_array($orig->childNodes);$cloneChildren = iterator_to_array($clone->childNodes);$j = 0;foreach ($origChildren as $child) {if ($child->nodeType !== XML_TEXT_NODE) {$map = $j < count($cloneChildren) ? $cloneChildren[$j] : null;if ($map) {$this->walkNodeAndMap($child, $map, $map);$j++;}}}}}/*** 更新命名映射表(domIdxToName 和 blocks)** 为克隆节点分配新名称(如 name#1),并注册到 blocks 中** @param \DOMNode $originalNode 原始节点* @param array $oldToNewMap 索引映射表* @param int $cloneIdx 克隆编号* @return void*/private function updateNameMappings($originalNode, $oldToNewMap, $cloneIdx){$begin = $originalNode->idxBegin;$end = $originalNode->idxEnd;for ($i = $begin; $i <= $end; $i++) {if (isset($this->domIdxToName[$i])) {$newIdx = $oldToNewMap[$i];$nameTemps = $this->domIdxToName[$i];foreach ($nameTemps as $key => $nameTemp) {$newName = $nameTemp[1] . '#' . $cloneIdx;$nameTemps[$key] = [$nameTemp[0], $newName];$this->blocks[$newName][$nameTemp[0]][] = $newIdx;}$this->domIdxToName[$newIdx] = $nameTemps;}}}/*** 更新扩展索引关联关系** 将原始节点的 idxExtendIdxs 映射到克隆节点** @param \DOMNode $originalNode 原始节点* @param array $oldToNewMap 索引映射表* @return void*/private function updateExtendIdxs($originalNode, $oldToNewMap){$begin = $originalNode->idxBegin;$end = $originalNode->idxEnd;for ($i = $begin; $i <= $end; $i++) {if (isset($this->idxExtendIdxs[$i])) {$newIdx = $oldToNewMap[$i];$this->idxExtendIdxs[$newIdx] = [];foreach ($this->idxExtendIdxs[$i] as $oldRefId) {if (isset($oldToNewMap[$oldRefId])) {$this->idxExtendIdxs[$newIdx][] = $oldToNewMap[$oldRefId];}}}}}
}

http://www.dtcms.com/a/324495.html

相关文章:

  • 绕过文件上传漏洞并利用文件包含漏洞获取系统信息的技术分析
  • 使用MongoDB存储和计算距离
  • Spring Boot 2 升级 Spring Boot 3 的全方位深度指南
  • Leetcode 3644. Maximum K to Sort a Permutation
  • 9_基于深度学习的车型检测识别系统(yolo11、yolov8、yolov5+UI界面+Python项目源码+模型+标注好的数据集)
  • Error: error:0308010C:digital envelope routines::unsupported at new Hash
  • 【Python 小脚本·大用途 · 第 3 篇】
  • 编译xformers
  • 【深度学习新浪潮】遥感图像风格化迁移研究工作介绍
  • 学习记录(十九)-Overleaf如何插入图片(单,多)
  • 学习模板元编程(3)enable_if
  • CART算法:Gini指数
  • 25.机器学习入门:让机器变聪明的魔法课
  • 串口通信初始化过程是怎样的???
  • IDEA 快捷编辑指南
  • Java开源代码源码研究:我的成长之路与实战心得分享
  • IDEA 安装插件的两种方式
  • 【面试场景题】异地多活改造方案
  • AI大模型--提示词工程
  • CVPR医学图像三套创新方案:通用分割+3D高效解码+SSM肿瘤定位(附链接)
  • 如何解决网站长期不连接数据库后首次连接缓慢的问题?
  • JS--判断是对象还是数组
  • Spring之【详解AOP】
  • 使用 Docker-Compose 部署 Redis 三主三从集群(含 Exporter 监控)
  • SQL Server从入门到项目实践(超值版)读书笔记 23
  • Windows 11 安装 JDK 11
  • ThreadLocal的原理是什么,使用场景有哪些?
  • 【自动化运维神器Ansible】playbook案例解析:Handlers与Notify机制深度解析
  • Vue3入门到精通:2.4 Vue3动态组件与异步组件深度解析
  • leetcode经典题目——单调栈