feat: export core Hermes skills
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
# Strip numPr Before Inserting Manual Numbering (2026-07-01)
|
||||
|
||||
## Problem
|
||||
|
||||
When adding manual numbering (e.g. "第一条 ") as `w:ins` at the beginning of a paragraph that already has `<w:numPr>` (automatic numbering like "%1." decimal format), OnlyOffice renders BOTH:
|
||||
- The automatic number: "1."
|
||||
- The manual INS text: "第一条"
|
||||
|
||||
Result: "1. 第一条 乙方应严格按照..."
|
||||
|
||||
## Root Cause
|
||||
|
||||
`<w:numPr>` in pPr tells the rendering engine to prepend an auto-generated number. The `w:ins` text is just another run in the paragraph — it doesn't suppress the auto-numbering.
|
||||
|
||||
Additionally, `<w:pPrChange>` records the pre-revision pPr state. If pPrChange still contains `<w:numPr>`, some renderers will show the old numbering in markup view.
|
||||
|
||||
## Affected Scenarios
|
||||
|
||||
1. **反委托代发工资协议 (2026-07-01)**: Original paragraphs P6-P12, P19 had `numId=1` or `numId=3` (decimal "%1." format). After adding "第一条" through "第十一条" as INS, OnlyOffice showed "1. 第一条", "2. 第二条", etc.
|
||||
|
||||
2. **Any contract where the original used auto-numbering**: Check `numbering.xml` for active numId references with `numFmt=decimal` or `numFmt=chineseCounting`.
|
||||
|
||||
## Fix Pattern
|
||||
|
||||
```python
|
||||
import zipfile
|
||||
from lxml import etree
|
||||
|
||||
WNS = '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}'
|
||||
|
||||
with zipfile.ZipFile(docx_path, 'r') as z:
|
||||
all_files = {name: z.read(name) for name in z.namelist()}
|
||||
|
||||
doc = etree.fromstring(all_files['word/document.xml'])
|
||||
body = doc.find(f'{WNS}body')
|
||||
paras = body.findall(f'{WNS}p')
|
||||
|
||||
# Identify paragraphs where we added manual numbering INS
|
||||
# These are paragraphs that have both:
|
||||
# 1. A w:ins with author=WB containing "第X条" text
|
||||
# 2. A pPr with numPr
|
||||
|
||||
for i, p in enumerate(paras):
|
||||
ppr = p.find(f'{WNS}pPr')
|
||||
if ppr is None:
|
||||
continue
|
||||
|
||||
# Check if this paragraph has our manual numbering INS
|
||||
has_manual_numbering = False
|
||||
for child in p:
|
||||
tag = child.tag.split('}')[-1] if '}' in child.tag else child.tag
|
||||
if tag == 'ins' and child.get(f'{WNS}author') == 'WB':
|
||||
text = ''.join(t.text for t in child.iter(f'{WNS}t') if t.text)
|
||||
if '第' in text and '条' in text:
|
||||
has_manual_numbering = True
|
||||
break
|
||||
|
||||
if not has_manual_numbering:
|
||||
continue
|
||||
|
||||
# Strip numPr from pPr
|
||||
num_pr = ppr.find(f'{WNS}numPr')
|
||||
if num_pr is not None:
|
||||
ppr.remove(num_pr)
|
||||
print(f"P{i}: Stripped numPr from pPr")
|
||||
|
||||
# Strip numPr from pPrChange
|
||||
ppc = ppr.find(f'{WNS}pPrChange')
|
||||
if ppc is not None:
|
||||
inner_ppr = ppc.find(f'{WNS}pPr')
|
||||
if inner_ppr is not None:
|
||||
inner_num = inner_ppr.find(f'{WNS}numPr')
|
||||
if inner_num is not None:
|
||||
inner_ppr.remove(inner_num)
|
||||
print(f"P{i}: Stripped numPr from pPrChange")
|
||||
|
||||
# Save back
|
||||
all_files['word/document.xml'] = etree.tostring(doc, xml_declaration=True, encoding='UTF-8', standalone=True)
|
||||
# Write to temp file then replace (never write to same zip you're reading)
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
After stripping, render with OnlyOffice and confirm:
|
||||
1. Markup view shows only the manual numbering (no "1." prefix)
|
||||
2. Accepted-revisions view shows clean "第一条" through "第十一条"
|
||||
3. python-docx can still open the file without errors
|
||||
|
||||
## Edge Cases
|
||||
|
||||
- **DEL-only empty paragraphs** (e.g. P8, P9 where all content is w:del): These may still have numPr. If they render a visible "3." or "4." in the gap, strip those too.
|
||||
- **Cross-paragraph clauses** (P6+P7 = one clause): P7 may have its own independent numPr even though it's a continuation paragraph. Strip it.
|
||||
- **numId=0 (disabled numbering)**: `numId=0` in OOXML means "numbering OFF" — it doesn't render anything. Only strip numPr where `numId > 0` and the corresponding abstractNum has a visible numFmt (decimal, chineseCounting, etc.).
|
||||
Reference in New Issue
Block a user