#!/usr/bin/env python3 """Post-save sweep: strip explicit attributes from WB INS runs when the same-paragraph original runs rely on inheritance (ea=None, hint=None, sz=None). Usage: python3 strip-inherited-ins-attrs.py Modifies the file in place. Run AFTER ContractEditor.save() and BEFORE wb-ins-font-verify.py to fix the known "ContractEditor默认sz=21与docDefaults继承冲突". The pattern: for each paragraph containing WB INS, find the first plain w:r (non-INS, non-DEL) as reference. If that reference run has no explicit eastAsia/hint/sz, strip those from all WB INS runs in the same paragraph. """ import sys import zipfile import tempfile import shutil from lxml import etree WNS = '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}' def strip_inherited_attrs(filepath): with zipfile.ZipFile(filepath, 'r') as z: doc_xml = z.read('word/document.xml') all_files = {n: z.read(n) for n in z.namelist()} tree = etree.fromstring(doc_xml) body = tree.find(f'{WNS}body') paras = body.findall(f'{WNS}p') fixed = 0 for p in paras: # Find first plain run as reference orig_run = None for child in p: if child.tag == f'{WNS}r': orig_run = child break if orig_run is None: continue orig_rpr = orig_run.find(f'{WNS}rPr') orig_rf = orig_rpr.find(f'{WNS}rFonts') if orig_rpr is not None else None orig_sz = orig_rpr.find(f'{WNS}sz') if orig_rpr is not None else None orig_ea = orig_rf.get(f'{WNS}eastAsia') if orig_rf is not None else None orig_hint = orig_rf.get(f'{WNS}hint') if orig_rf is not None else None orig_sz_val = orig_sz.get(f'{WNS}val') if orig_sz is not None else None for ins in p.findall(f'.//{WNS}ins'): if ins.get(f'{WNS}author') != 'WB': continue for r in ins.findall(f'{WNS}r'): rpr = r.find(f'{WNS}rPr') if rpr is None: continue rf = rpr.find(f'{WNS}rFonts') sz = rpr.find(f'{WNS}sz') if orig_ea is None and rf is not None: for attr in ['eastAsia', 'ascii', 'hAnsi']: key = f'{WNS}{attr}' if key in rf.attrib: if orig_rf is None or orig_rf.get(key) is None: del rf.attrib[key] fixed += 1 if orig_hint is None and rf is not None and f'{WNS}hint' in rf.attrib: del rf.attrib[f'{WNS}hint'] fixed += 1 if orig_sz_val is None and sz is not None: rpr.remove(sz) fixed += 1 # Save tmp = tempfile.mktemp(suffix='.docx') with zipfile.ZipFile(tmp, 'w', zipfile.ZIP_DEFLATED) as zout: for name in all_files: if name == 'word/document.xml': new_xml = etree.tostring(tree, xml_declaration=True, encoding='UTF-8', standalone=True) new_str = new_xml.decode('utf-8') new_str = new_str.replace( "", '') new_str = new_str.replace('\n', '\r\n') zout.writestr(name, new_str.encode('utf-8')) else: zout.writestr(name, all_files[name]) shutil.move(tmp, filepath) return fixed if __name__ == '__main__': if len(sys.argv) < 2: print(f"Usage: {sys.argv[0]} ") sys.exit(1) n = strip_inherited_attrs(sys.argv[1]) print(f"Fixed {n} inherited attribute issues in {sys.argv[1]}")