2.7 KiB
2.7 KiB
A类手动编号顺延 — 段落级 DEL/INS 模式
实战来源:CT维保合同-香花桥(2026-06-26)。新增"9. 第三方侵权"条款后,需将原9→10、10→11、11→12、12→13、13→14 顺延。所有条款编号均为手动文本(A类,run内w:t文字,无numPr)。
核心模式
对每个需顺延的段落,找到包含旧编号的 run,用段落级 DEL/INS 替换:
for old_num, new_num in renumber_map.items():
for r in p.findall(f'{{{W}}}r'):
t = r.find(f'{{{W}}}t')
if t is None or t.text is None: continue
if t.text.strip().startswith(str(old_num)):
# 1. DEL run: 旧编号
del_run = deepcopy(r)
del_run.set(f'{{{W}}}rsidDel', rsid)
del_t = del_run.find(f'{{{W}}}t')
del_t.tag = f'{{{W}}}delText'
del_t.text = str(old_num)
del_w = etree.Element(f'{{{W}}}del')
del_w.set(f'{{{W}}}id', str(nid)); nid += 1
del_w.set(f'{{{W}}}author', 'WB')
del_w.set(f'{{{W}}}date', rev_date)
del_w.append(del_run)
# 2. INS run: 新编号
ins_run = deepcopy(r)
ins_run.set(f'{{{W}}}rsidR', rsid)
ins_t = ins_run.find(f'{{{W}}}t')
ins_t.text = str(new_num)
ins_w = etree.Element(f'{{{W}}}ins')
ins_w.set(f'{{{W}}}id', str(nid)); nid += 1
ins_w.set(f'{{{W}}}author', 'WB')
ins_w.set(f'{{{W}}}date', rev_date)
ins_w.append(ins_run)
# 3. 原 run 去掉编号前缀
t.text = t.text[len(str(old_num)):]
# 4. DEL + INS 插入在原 run 之前
r.addprevious(ins_w)
r.addprevious(del_w)
break
break # 每个段落只改一个编号
关键点
- DEL/INS 在段落级(
w:p的直接子元素),不是 run 内 - 从后往前处理:如果用索引遍历,从后往前避免 offset 漂移
- 只匹配run开头:
t.text.strip().startswith(str(old_num))确保只匹配编号前缀 - 原 run 保留剩余文本:
t.text = t.text[len(str(old_num)):]去掉编号后保留标题文字 - ID 递增:每个 DEL/INS 用独立 id,从
max_id + 1起
与 add_clause 的区别
add_clause/add_clause_before:创建全新段落(整段 w:ins)- 本模式:修改已有段落的第一个 run 的编号,其余内容不动
适用场景
- 新增条款后,后续手动编号(A类)的条款需要顺延
- 不适用于自动编号(B类)——自动编号由 number.xml 引擎处理,修改 run 内文字无效