all in
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
# 占位符提取功能修复总结
|
||||
|
||||
## 问题描述
|
||||
|
||||
在测试占位符提取功能时,发现使用 `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 文件**
|
||||
```typescript
|
||||
const zip = new PizZip(content);
|
||||
```
|
||||
|
||||
2. **直接读取 document.xml**
|
||||
```typescript
|
||||
const documentXml = zip.file('word/document.xml');
|
||||
const xmlContent = documentXml.asText();
|
||||
```
|
||||
|
||||
3. **移除所有 XML 标签,只保留纯文本**
|
||||
```typescript
|
||||
const fullText = xmlContent.replace(/<[^>]+>/g, '');
|
||||
```
|
||||
|
||||
4. **使用正则表达式提取占位符**
|
||||
```typescript
|
||||
const placeholderRegex = /\{\{([^}]+)\}\}/g;
|
||||
const matches = fullText.matchAll(placeholderRegex);
|
||||
```
|
||||
|
||||
### 优势
|
||||
|
||||
✅ **避免格式化问题** - 不受 Word 文档格式化的影响
|
||||
✅ **更简单** - 不需要创建 docxtemplater 实例
|
||||
✅ **更快** - 跳过编译步骤,直接提取
|
||||
✅ **更可靠** - 适用于任何格式化的 docx 文件
|
||||
|
||||
## 修改的文件
|
||||
|
||||
### 1. `app/api/contracts/docx-parser.server.ts`
|
||||
|
||||
**修改前**:使用 docxtemplater.getFullText()
|
||||
```typescript
|
||||
const doc = new Docxtemplater(zip, {
|
||||
paragraphLoop: true,
|
||||
linebreaks: true,
|
||||
});
|
||||
const fullText = doc.getFullText();
|
||||
```
|
||||
|
||||
**修改后**:直接读取 XML
|
||||
```typescript
|
||||
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.js` → `test-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. 测试一键替换功能
|
||||
Reference in New Issue
Block a user