#!/usr/bin/env python3 """生成"接受所有修订后"的干净 docx,用于 OnlyOffice 渲染做字体/排版的决定性视觉验证。 为什么需要:OnlyOffice 渲染修订态文字(w:ins,紫色+下划线)时视觉上常显示为类无衬线、 看起来字体/粗细与正文不同——这是 track-changes 的渲染特性,不是真实字体差异。vision 工具 会据此误报"字体不一致",导致无谓返工。把所有修订接受、批注去掉后再渲染,才能在无修订 颜色干扰下看到插入文字与正文的真实字体一致性。 用法: python accept-revisions-preview.py 处理: 解包所有 w:ins(保留内容)+ 删除所有 w:del(连内容)+ 移除批注锚点标记。 注意: 产物仅供"渲染核对",不是正式交付物(交付的是带修订痕迹的版本)。 """ import sys, zipfile, io from lxml import etree W = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main' Wq = '{' + W + '}' def accept_revisions(in_path, out_path): with open(in_path, 'rb') as f: data = f.read() bin_, bout = io.BytesIO(data), io.BytesIO() with zipfile.ZipFile(bin_) as zin, zipfile.ZipFile(bout, 'w', zipfile.ZIP_DEFLATED) as zout: for item in zin.infolist(): raw = zin.read(item.filename) if item.filename == 'word/document.xml': root = etree.fromstring(raw) # 删除所有 w:del(含内容) for d in [e for e in root.iter(Wq + 'del')]: d.getparent().remove(d) # 解包所有 w:ins:把子元素提到 ins 的位置后删除 ins 壳 for ins in [e for e in root.iter(Wq + 'ins')]: parent = ins.getparent() idx = list(parent).index(ins) for child in reversed(list(ins)): parent.insert(idx, child) parent.remove(ins) # 移除批注锚点标记 for tag in ('commentRangeStart', 'commentRangeEnd'): for e in [x for x in root.iter(Wq + tag)]: e.getparent().remove(e) for r in [x for x in root.iter(Wq + 'r')]: if r.find(Wq + 'commentReference') is not None: r.getparent().remove(r) raw = etree.tostring(root, xml_declaration=True, encoding='UTF-8', standalone=True) zout.writestr(item, raw) with open(out_path, 'wb') as f: f.write(bout.getvalue()) print(f'接受修订版已生成: {out_path}') if __name__ == '__main__': if len(sys.argv) != 3: print('用法: python accept-revisions-preview.py ') sys.exit(1) accept_revisions(sys.argv[1], sys.argv[2])