feat: export core Hermes skills
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
# Strip numPr When Adding Manual Numbering to Auto-Numbered Paragraphs
|
||||
|
||||
## Problem (2026-07-01 反委托代发工资协议)
|
||||
|
||||
Original contract paragraphs have `<w:numPr>` with actual auto-numbering (e.g., `numId=3 → abstractNum decimal "%1." start=1`). When you insert manual "第X条" numbering as `w:ins` at paragraph start, OnlyOffice renders BOTH:
|
||||
|
||||
```
|
||||
1. 第一条 乙方应严格按照... ← "1." is auto-numbering, "第一条" is your INS
|
||||
```
|
||||
|
||||
This looks broken — two different numbering systems stacked.
|
||||
|
||||
## Root Cause
|
||||
|
||||
The paragraph's `pPr/numPr` tells the rendering engine to prepend an automatic decimal number. Your INS adds a second, manual number. They coexist independently.
|
||||
|
||||
Additionally, if the paragraph has `pPr/pPrChange` (tracking the old paragraph formatting), the old `numPr` inside `pPrChange` can ALSO render in markup view.
|
||||
|
||||
## Fix (two-step)
|
||||
|
||||
After inserting manual numbering INS elements, strip auto-numbering from ALL affected paragraphs:
|
||||
|
||||
```python
|
||||
for idx in target_paragraph_indices:
|
||||
p = paras[idx]
|
||||
ppr = p.find(f'{WNS}pPr')
|
||||
if ppr is not None:
|
||||
# Step 1: Remove direct numPr
|
||||
num_pr = ppr.find(f'{WNS}numPr')
|
||||
if num_pr is not None:
|
||||
ppr.remove(num_pr)
|
||||
|
||||
# Step 2: Remove numPr inside pPrChange (old formatting record)
|
||||
ppr_change = ppr.find(f'{WNS}pPrChange')
|
||||
if ppr_change is not None:
|
||||
inner_ppr = ppr_change.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)
|
||||
```
|
||||
|
||||
## When This Applies
|
||||
|
||||
- You're converting a contract from auto-numbered clauses to manual "第X条" heading-style numbering
|
||||
- The original .doc/.docx used Word's list numbering for clause structure
|
||||
- You're adding "第一条 " etc. as INS at paragraph start
|
||||
|
||||
## Verification
|
||||
|
||||
After fix:
|
||||
1. `pdftotext -layout` of OnlyOffice render should show NO stray "1." / "2." / "3." before your "第X条"
|
||||
2. Accept-revisions preview should also be clean (no residual auto-numbers)
|
||||
|
||||
## Scenario B: Auto-Numbering Resets Across Tracked-Deleted Paragraphs (2026-07-01 反委托代发工资协议)
|
||||
|
||||
### Problem
|
||||
|
||||
When paragraphs with `numPr` auto-numbering are interspersed with **entirely deleted paragraphs** (all content in `w:del`), OnlyOffice's auto-number counter **resets to 1** after the deleted block. This makes continuous numbering impossible with `numPr` alone.
|
||||
|
||||
Example structure:
|
||||
```
|
||||
P6: numPr=1 INS content (clause 1) → renders "1."
|
||||
P7: numPr=1 continuation → renders "2." (wrong if P7 shouldn't be numbered)
|
||||
P8: numPr=1 ALL w:del → renders "3." with strikethrough
|
||||
P9: numPr=1 ALL w:del → renders "4." with strikethrough
|
||||
P10: numPr=1 INS content (clause 2) → renders "1." ← RESETS! Should be "2."
|
||||
```
|
||||
|
||||
The auto-numbering engine counts visible (non-deleted) items in the `numId` sequence, but deleted paragraphs **break the continuity** in OnlyOffice's rendering.
|
||||
|
||||
### Solution: Convert to Manual Text Numbering
|
||||
|
||||
Strip `numPr` from ALL paragraphs and insert "N. " as `w:ins` text at paragraph start. This gives identical visual output ("1. 2. 3. ...") without depending on the broken auto-number counter.
|
||||
|
||||
```python
|
||||
# Step 1: Strip ALL numPr (including inside pPrChange)
|
||||
for i, p in enumerate(paragraphs):
|
||||
pPr = p.find(f'{{{W}}}pPr')
|
||||
if pPr is not None:
|
||||
numPr = pPr.find(f'{{{W}}}numPr')
|
||||
if numPr is not None:
|
||||
pPr.remove(numPr)
|
||||
for pPrChange in pPr.findall(f'{{{W}}}pPrChange'):
|
||||
old_pPr = pPrChange.find(f'{{{W}}}pPr')
|
||||
if old_pPr is not None:
|
||||
old_numPr = old_pPr.find(f'{{{W}}}numPr')
|
||||
if old_numPr is not None:
|
||||
old_pPr.remove(old_numPr)
|
||||
|
||||
# Step 2: Insert "N. " as w:ins text for each clause paragraph
|
||||
# Only number paragraphs that have VISIBLE content (not entirely w:del)
|
||||
clause_map = {6: 1, 10: 2, 11: 3, ...} # para_index: clause_number
|
||||
|
||||
for para_idx, clause_num in clause_map.items():
|
||||
p = paragraphs[para_idx]
|
||||
# Build INS element with "N. " text
|
||||
ins_elem = ET.Element(f'{{{W}}}ins')
|
||||
ins_elem.set(f'{{{W}}}id', str(next_rev_id()))
|
||||
ins_elem.set(f'{{{W}}}author', rev_author) # from existing INS in doc
|
||||
ins_elem.set(f'{{{W}}}date', rev_date)
|
||||
|
||||
r_elem = ET.SubElement(ins_elem, f'{{{W}}}r')
|
||||
# Clone rPr from existing runs for font consistency
|
||||
rPr = get_run_rPr_from_paragraph(p)
|
||||
if rPr is not None:
|
||||
r_elem.append(copy.deepcopy(rPr))
|
||||
|
||||
t_elem = ET.SubElement(r_elem, f'{{{W}}}t')
|
||||
t_elem.set('{http://www.w3.org/XML/1998/namespace}space', 'preserve')
|
||||
t_elem.text = f"{clause_num}. "
|
||||
|
||||
# Insert after pPr
|
||||
pPr = p.find(f'{{{W}}}pPr')
|
||||
if pPr is not None:
|
||||
p.insert(list(p).index(pPr) + 1, ins_elem)
|
||||
else:
|
||||
p.insert(0, ins_elem)
|
||||
```
|
||||
|
||||
### When to Use This (vs Scenario A)
|
||||
|
||||
- **Scenario A** (above): You're CHANGING the numbering scheme (auto "1." → manual "第一条")
|
||||
- **Scenario B** (this): You're KEEPING the same format ("1. 2. 3.") but converting from auto to manual because auto-numbering resets across w:del paragraphs
|
||||
- **Trigger**: Original uses numPr auto-numbering + your edits create entirely-deleted paragraphs between numbered items → auto counter resets → switch to manual text
|
||||
|
||||
### Key Decision: Which Paragraphs to Number
|
||||
|
||||
Only number paragraphs that will be visible after accepting revisions:
|
||||
- Paragraphs with ONLY `w:del` content → skip (they're deleted)
|
||||
- Paragraphs that are continuations of the previous clause (no independent number) → skip
|
||||
- New INS-only paragraphs (new clauses) → number them
|
||||
- Rewritten paragraphs (mixed INS+DEL, first clause in sequence) → number them
|
||||
|
||||
### Verification
|
||||
|
||||
After conversion:
|
||||
1. OnlyOffice render (x2t → PDF) should show continuous "1. 2. 3. ... 11." without resets
|
||||
2. No stray auto-numbers from numPr remnants
|
||||
3. Deleted paragraphs (entirely w:del) should NOT show any number
|
||||
|
||||
## Distinction from Existing Rules
|
||||
|
||||
- Rule 5 (A類 vs B類) talks about NEW clauses inheriting/stripping numPr
|
||||
- Scenario A is EXISTING paragraphs where you're REPLACING their numbering scheme with a different format via INS
|
||||
- Scenario B is EXISTING paragraphs where auto-numbering BREAKS due to tracked-deleted paragraphs, requiring conversion to same-format manual text
|
||||
- numId=0 trap (Rule 5 sub-note) is about fake auto-numbering; BOTH scenarios here are about REAL auto-numbering that renders visible numbers
|
||||
Reference in New Issue
Block a user