Files

100 lines
3.8 KiB
Python

#!/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 <docx_path>
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(
"<?xml version='1.0' encoding='UTF-8' standalone='yes'?>",
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>')
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]} <docx_path>")
sys.exit(1)
n = strip_inherited_attrs(sys.argv[1])
print(f"Fixed {n} inherited attribute issues in {sys.argv[1]}")