feat: export core Hermes skills
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# add_clause after_search Fails After tracked_replace — Use Direct lxml Insertion
|
||||
|
||||
## Problem (2026-07-01 凤雅幼儿园劳务派遣协议)
|
||||
|
||||
After calling `ed.tracked_replace(old, new)` on multiple paragraphs, subsequent `ed.add_clause(text, after_search="...")` calls silently fail — the new paragraph doesn't appear in the output. The function returns without error but the clause is not inserted.
|
||||
|
||||
## Root Cause
|
||||
|
||||
`add_clause`'s `after_search` parameter searches paragraph text by concatenating all `<w:t>` elements. After `tracked_replace`, the paragraph's XML contains interleaved `<w:del>` and `<w:ins>` elements. The `after_search` text-matching logic may:
|
||||
|
||||
1. Include both old (del) and new (ins) text in the concatenation, so neither the old NOR new text matches cleanly
|
||||
2. Match the wrong paragraph if the search string appears in unexpected combinations of del+ins text
|
||||
|
||||
## Solution: Direct lxml `addnext` Insertion
|
||||
|
||||
After all `tracked_replace` calls, insert new clauses directly using lxml:
|
||||
|
||||
```python
|
||||
# Find reference paragraph by index or by scanning accepted-view text
|
||||
paras = ed.body.findall(f'{WNS}p')
|
||||
ref_para = paras[target_index] # e.g., P68
|
||||
|
||||
# Build INS paragraph
|
||||
new_p = etree.Element(f'{WNS}p')
|
||||
new_p.append(copy.deepcopy(ref_ppr)) # Clone paragraph formatting
|
||||
|
||||
ins = etree.SubElement(new_p, f'{WNS}ins')
|
||||
ins.set(f'{WNS}id', next_rev_id())
|
||||
ins.set(f'{WNS}author', 'WB')
|
||||
ins.set(f'{WNS}date', rev_date)
|
||||
|
||||
r = etree.SubElement(ins, f'{WNS}r')
|
||||
r.set(f'{WNS}rsidR', rsid)
|
||||
r.insert(0, copy.deepcopy(ref_rpr))
|
||||
|
||||
t = etree.SubElement(r, f'{WNS}t')
|
||||
t.set(XML_SPACE, 'preserve')
|
||||
t.text = clause_text
|
||||
|
||||
# Mark paragraph itself as inserted (pPr/rPr/ins)
|
||||
ppr = new_p.find(f'{WNS}pPr')
|
||||
ppr_rpr = etree.SubElement(ppr, f'{WNS}rPr')
|
||||
ppr_ins = etree.SubElement(ppr_rpr, f'{WNS}ins')
|
||||
ppr_ins.set(f'{WNS}id', next_rev_id())
|
||||
ppr_ins.set(f'{WNS}author', 'WB')
|
||||
ppr_ins.set(f'{WNS}date', rev_date)
|
||||
|
||||
# Insert after reference
|
||||
ref_para.addnext(new_p)
|
||||
ref_para = new_p # Chain subsequent inserts
|
||||
```
|
||||
|
||||
## When This Applies
|
||||
|
||||
- You need to both modify existing clauses (tracked_replace) AND add new clauses in the same editing session
|
||||
- The `after_search` text has been altered by prior tracked_replace calls
|
||||
|
||||
## Correct Operation Order
|
||||
|
||||
1. All `ed.tracked_replace(...)` calls first
|
||||
2. Then find target paragraphs by scanning the body with accepted-view text extraction
|
||||
3. Insert new paragraphs directly via `addnext`
|
||||
4. `ed.validate()` + `ed.save()`
|
||||
|
||||
## Verification
|
||||
|
||||
After save, scan paragraphs and confirm new clauses appear in accepted-view text at the expected positions.
|
||||
Reference in New Issue
Block a user