All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 6s
Documents the rules and decisions behind building DOCX files from דפנה's
decision template (טיוטת החלטה.dotx). The implementation lives in
mcp-server/src/legal_mcp/services/analysis_docx_exporter.py; this skill
captures the "why" so future improvements don't need to rediscover it.
Contents:
SKILL.md 5 critical rules, style mapping table,
export flow, line classification,
dash policy, placeholder handling,
troubleshooting, future TODOs
references/dotx-to-docx.md why python-docx can't open .dotx +
the conversion recipe
references/rtl-runs.md why <w:rtl/> is required on every run
(otherwise Hebrew falls back to
Times New Roman)
references/style-mapping.md XML dump of every template style,
with the Title-via-theme gotcha
references/line-classification.md the 7 regex categories in
_classify_line() with real examples
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
156 lines
5.4 KiB
Markdown
156 lines
5.4 KiB
Markdown
# מיפוי סגנונות — `טיוטת החלטה.dotx`
|
||
|
||
מבוסס על ניתוח `word/styles.xml` של הטמפלט. כל הגדרות מצוטטות מה-XML
|
||
המקורי.
|
||
|
||
## סגנונות בסיסיים (Word-idioms)
|
||
|
||
### `Normal` (styleId: `a1`)
|
||
ברירת המחדל לפסקאות רגילות. **כל שאר הסגנונות יורשים ממנו**
|
||
(`basedOn="a1"`).
|
||
|
||
```xml
|
||
<rPr>
|
||
<rFonts ascii="Times New Roman" hAnsi="Times New Roman" cs="David"/>
|
||
<sz val="26"/> <!-- 13pt -->
|
||
<szCs val="26"/>
|
||
</rPr>
|
||
<pPr>
|
||
<bidi/> <!-- RTL -->
|
||
<spacing before="120" after="120" line="360" lineRule="auto"/>
|
||
<ind left="-454"/> <!-- negative left indent -->
|
||
<jc val="both"/> <!-- justify -->
|
||
</pPr>
|
||
```
|
||
|
||
**מה זה אומר לך:**
|
||
- עברית תצא ב-David 13pt (דרך `cs`)
|
||
- לטינית תצא ב-Times New Roman 13pt (דרך `ascii`)
|
||
- יישור justify (דו-צדדי), RTL
|
||
- מרווח 1.5 שורות (`line=360` = 1.5 × 240)
|
||
|
||
### `Heading 1` (styleId: `10`, name: `heading 1`)
|
||
לכותרת ראשית (כמו "ניתוח משפטי וכתיבת עמדה בערר X").
|
||
```xml
|
||
<basedOn val="a1"/> <!-- יורש מ-Normal → cs="David" -->
|
||
<rPr><rFonts asciiTheme="majorHAnsi" .../><sz val="40"/></rPr> <!-- 20pt -->
|
||
```
|
||
Heading 1 **אינו** מציין cs fonts מפורשות, אבל יורש `cs="David"` מ-Normal.
|
||
זה מבדיל אותו מ-`Title`, שמפנה ל-theme ריק.
|
||
|
||
### `Heading 2` (styleId: `2`)
|
||
לכותרות מקטעים ותת-מקטעים.
|
||
```xml
|
||
<basedOn val="a1"/>
|
||
<pPr><keepNext/><spacing before="160"/><ind left="-567"/></pPr>
|
||
<rPr><b/><bCs/><u val="single"/></rPr> <!-- bold + underline -->
|
||
```
|
||
|
||
### `Title` (styleId: `a5`) — ⚠️ הימנע
|
||
```xml
|
||
<rPr><rFonts asciiTheme="majorHAnsi" cstheme="majorBidi" .../></rPr>
|
||
```
|
||
מפנה ל-theme. ב-`theme1.xml`: `majorFont.cs = ""` (ריק). → עברית נופלת
|
||
ל-`majorFont.latin = "Aptos Display"`. **השתמש ב-Heading 1 במקום.**
|
||
|
||
### `Subtitle` (styleId: `a7`) — ⚠️ אותה בעיה של Title
|
||
לא בשימוש.
|
||
|
||
## סגנונות תוכן
|
||
|
||
### `Quote` (styleId: `a9`)
|
||
```xml
|
||
<basedOn val="a1"/>
|
||
<pPr><spacing before="0" after="0" line="276"/>
|
||
<ind left="680" right="170"/></pPr> <!-- הזחה דו-צדדית -->
|
||
<rPr><b/><bCs/></rPr> <!-- bold -->
|
||
```
|
||
לציטוטי פסיקה. הזחה פנימה, bold.
|
||
|
||
### `List Paragraph` (styleId: `a0`)
|
||
```xml
|
||
<basedOn val="a1"/>
|
||
<pPr>
|
||
<numPr><numId val="1"/></numPr> <!-- auto-numbering -->
|
||
<spacing after="0"/>
|
||
<ind left="-125" hanging="357"/>
|
||
</pPr>
|
||
<rPr><rFonts ascii="David" hAnsi="David"/><sz val="28"/></rPr> <!-- 14pt -->
|
||
```
|
||
**numId=1 מפנה ל-abstractNumId=16**, שמוגדר כ-`decimal` עם `lvlText="%1."`.
|
||
כלומר Word יוסיף "1.", "2.", "3." אוטומטית לפני הטקסט.
|
||
|
||
**חשוב:** `List Paragraph` הוא היחיד בטמפלט עם numbering אוטומטי. אין
|
||
bullet style מוכן. לרשימות עם (א)(ב), **הסר את ה-numPr** ברמת הפסקה:
|
||
|
||
```python
|
||
from docx.oxml.ns import qn
|
||
|
||
def _strip_numpr(paragraph):
|
||
pPr = paragraph._p.get_or_add_pPr()
|
||
for numPr in pPr.findall(qn("w:numPr")):
|
||
pPr.remove(numPr)
|
||
```
|
||
|
||
## סגנונות נוספים בטמפלט (לא בשימוש כרגע)
|
||
|
||
| styleId | שם | מה |
|
||
|---------|----|----|
|
||
| `P00`, `P11`, `P22` | תבניות מותאמות אישית | ישן, נראה שלא בשימוש פעיל |
|
||
| `12`, `21`, `31` | פיסקת רשימה 1/2/3 | ללא numPr — שימוש ויזואלי בלבד |
|
||
| `-` | פיסקת רשימה - ללא מספור | מיועד ל-bullets ללא מספור |
|
||
| `14` | ציטוט1 | וריאציה ישנה של Quote |
|
||
| `af2` / `af4` | header / footer | לכותרות עליונות/תחתונות |
|
||
|
||
## theme (`word/theme/theme1.xml`)
|
||
|
||
```xml
|
||
<majorFont>
|
||
<latin typeface="Aptos Display"/>
|
||
<cs typeface=""/> <!-- ריק! -->
|
||
</majorFont>
|
||
<minorFont>
|
||
<latin typeface="Aptos"/>
|
||
<cs typeface=""/> <!-- ריק! -->
|
||
</minorFont>
|
||
```
|
||
|
||
**ה-cs ריק ב-theme** — זו הסיבה ש-`Title` (שמפנה ל-theme) לא עובד
|
||
לעברית. אל תסמוך על theme; השתמש ב-styles שמגדירים cs מפורש (Normal +
|
||
כל מה שיורש ממנו).
|
||
|
||
## numbering definitions
|
||
|
||
`word/numbering.xml` כולל ~22 abstractNum מוגדרים. הרלוונטי לנו:
|
||
|
||
```
|
||
numId=1 → abstractNumId=16 → numFmt=decimal, lvlText="%1."
|
||
```
|
||
|
||
יש גם hebrew1 (`numFmt=hebrew1` = א., ב., ג.) ב-`abstractNumId=0, 1`.
|
||
אף סגנון מוכן לא מפנה אליהם. אם תרצה בעתיד רשימה ממוספרת בעברית עם
|
||
Word auto-numbering — יש להזריק `numPr` ידנית עם `numId=29` (שמפנה
|
||
ל-abstractNumId=0).
|
||
|
||
## גדלים — רפרנס מהיר
|
||
|
||
| style | ascii | cs (עברית) |
|
||
|-------|-------|-----------|
|
||
| Normal | 13pt | 13pt |
|
||
| Heading 1 | 20pt | 18pt |
|
||
| Heading 2 | 13pt (ירושה) + bold + underline | אותו דבר |
|
||
| Title | 28pt (Aptos Display — לא עברית!) | — |
|
||
| List Paragraph | 14pt (David) | 14pt |
|
||
| Quote | 13pt (ירושה) + bold | 13pt |
|
||
|
||
## טיפ
|
||
|
||
כדי לבדוק את כל הסגנונות שבמסמך:
|
||
|
||
```python
|
||
from docx import Document
|
||
d = Document("skills/docx/decision_template.docx")
|
||
for s in sorted(d.styles, key=lambda x: x.name):
|
||
print(s.type, s.name, s.style_id)
|
||
```
|