Files
leaudit-platform-frontend/docs/placeholder-extraction-fix-summary.md
2025-12-05 00:09:32 +08:00

4.1 KiB

占位符提取功能修复总结

问题描述

在测试占位符提取功能时,发现使用 docxtemplater 库的 getFullText() 方法会因为 Word 文档中的格式化(粗体、斜体等)导致占位符标签被分割成多个 XML 元素,从而引发编译错误。

原始错误

Error: Duplicate open tag, expected one open tag
Error: Duplicate close tag, expected one close tag

这是因为 Word 文档中的 {{占位符}} 可能被格式化标签分割,例如:

  • {{地市名称}} 可能在 XML 中被分割为 {{地市名称}}
  • 这导致 docxtemplater 在编译时检测到重复的开/闭标签

解决方案

核心思路

不使用 docxtemplater 进行编译,而是直接读取 word/document.xml 文件,移除 XML 标签后提取占位符。

实现步骤

  1. 使用 PizZip 解压 docx 文件

    const zip = new PizZip(content);
    
  2. 直接读取 document.xml

    const documentXml = zip.file('word/document.xml');
    const xmlContent = documentXml.asText();
    
  3. 移除所有 XML 标签,只保留纯文本

    const fullText = xmlContent.replace(/<[^>]+>/g, '');
    
  4. 使用正则表达式提取占位符

    const placeholderRegex = /\{\{([^}]+)\}\}/g;
    const matches = fullText.matchAll(placeholderRegex);
    

优势

避免格式化问题 - 不受 Word 文档格式化的影响 更简单 - 不需要创建 docxtemplater 实例 更快 - 跳过编译步骤,直接提取 更可靠 - 适用于任何格式化的 docx 文件

修改的文件

1. app/api/contracts/docx-parser.server.ts

修改前:使用 docxtemplater.getFullText()

const doc = new Docxtemplater(zip, {
  paragraphLoop: true,
  linebreaks: true,
});
const fullText = doc.getFullText();

修改后:直接读取 XML

const documentXml = zip.file('word/document.xml');
const xmlContent = documentXml.asText();
const fullText = xmlContent.replace(/<[^>]+>/g, '');

2. scripts/test-docx-parser.cjs

  • 重命名:test-docx-parser.jstest-docx-parser.cjs(适配 ES 模块项目)
  • 移除了 docxtemplater 依赖
  • 使用相同的 XML 读取方法

3. docs/docxtemplater-placeholder-extraction.md

更新文档以反映新的实现方式:

  • 技术栈:移除 docxtemplater,强调使用 pizzip + 正则表达式
  • 工作流程:更新为直接读取 XML 的流程
  • 代码示例:更新为新的实现

测试结果

运行 node scripts/test-docx-parser.cjs 成功提取了 18 个占位符:

✅ 文件读取成功, 大小: 18.95 KB
✅ PizZip 解压成功
✅ document.xml 读取成功
✅ XML 内容长度: 33378
✅ 提取纯文本成功
文本长度: 5047

找到 18 个占位符:
1. {{地市名称}}
2. {{合同名称}}
3. {{合同编号}}
4. {{项目编号}}
5. {{市名}}
6. {{区名}}
7. {{年}}
8. {{月}}
9. {{日}}
10. {{有效期限}}
11. {{甲方名称}}
12. {{甲方注册地址}}
13. {{甲方法定代表人}}
14. {{甲方联系电话}}
15. {{乙方名称}}
16. {{乙方注册地址}}
17. {{乙方法定代表人}}
18. {{乙方联系电话}}

智能分类

系统自动推测了字段类型和分组:

  • 基本信息:地市名称、合同名称、合同编号等
  • 甲方信息:甲方名称、甲方注册地址(textarea)、甲方法定代表人、甲方联系电话
  • 乙方信息:乙方名称、乙方注册地址(textarea)、乙方法定代表人、乙方联系电话

类型检查

运行 npm run typecheck 确认没有引入新的类型错误。所有显示的错误都是代码库中的既有问题,与本次修改无关。

总结

问题已解决 - 占位符提取功能正常工作 测试通过 - 成功从测试文档中提取 18 个占位符 类型安全 - 没有引入新的 TypeScript 错误 文档更新 - 文档已更新以反映新的实现方式

功能已经可以集成到实际应用中使用。下一步可以:

  1. 启动开发服务器测试完整流程
  2. 验证占位符表单渲染
  3. 测试一键替换功能