
Docx Format Replicator
- 620 installs
- 303 repo stars
- Updated April 20, 2026
- iamzhihuix/happy-claude-skills
docx-format-replicator is a Claude skill at version 1.0.0 that extracts formatting from an existing Word document and generates new documents matching its style, fonts, headings, and layout for developers who need consis
About
docx-format-replicator is a happy-claude-skills agent skill at version 1.0.0 that reads an existing .docx file, extracts its formatting metadata—fonts, headings, styles, and layout—and writes new Word documents with identical presentation but different body content. Developers reach for docx-format-replicator when generating batches of reports, proposals, or compliance documents that must match a master template without manual copy-paste formatting. The skill supports corporate document standards and template replication across multiple outputs from a single reference file.
- Extracts formatting from any .docx template into reusable JSON
- Generates new documents that perfectly replicate corporate or branded styles
- Supports creating multiple consistent documents from one template
- Handles complex Word structures including headings, lists, tables and styles
- CLI-based workflow with extract_format.py and generate_document.py scripts
Docx Format Replicator by the numbers
- 620 all-time installs (skills.sh)
- +14 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #356 of 1,879 Documentation skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/iamzhihuix/happy-claude-skills --skill docx-format-replicatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 620 |
|---|---|
| repo stars | ★ 303 |
| Last updated | April 20, 2026 |
| Repository | iamzhihuix/happy-claude-skills ↗ |
How do you replicate Word document formatting in new files?
Extract formatting from an existing Word document and generate new documents that match its style, fonts, headings, and layout while using fresh content.
Who is it for?
Developers automating Word document generation who must preserve corporate formatting from an existing .docx template.
Skip if: Developers working in Markdown, PDF-only pipelines, or unstructured plain text without .docx templates should skip docx-format-replicator.
When should I use this skill?
A user needs multiple Word documents with consistent formatting cloned from an existing .docx reference file.
What you get
New .docx files with extracted fonts, heading styles, and layout applied to fresh content matching the source template.
- formatted .docx files
- replicated document template
- style metadata extraction
By the numbers
- Skill version 1.0.0
Files
DOCX Format Replicator
Overview
Extract formatting information from existing Word documents (.docx) and use it to generate new documents with identical formatting but different content. This skill enables creating document templates, maintaining consistent formatting across multiple documents, and replicating complex Word document structures.
When to Use This Skill
Use this skill when the user:
- Wants to extract formatting from an existing Word document
- Needs to create multiple documents with the same format
- Has a template document and wants to generate similar documents with new content
- Asks to "replicate", "copy format", "use the same style", or "create a document like"
- Mentions document templates, corporate standards, or format consistency
Workflow
Step 1: Extract Format from Template
Extract formatting information from an existing Word document to create a reusable format configuration.
python scripts/extract_format.py <template.docx> <output.json>Example:
python scripts/extract_format.py "HY研制任务书.docx" format_template.jsonWhat Gets Extracted:
- Style definitions (fonts, sizes, colors, alignment)
- Paragraph and character styles
- Numbering schemes (1, 1.1, 1.1.1, etc.)
- Table structures and styles
- Header and footer configurations
Output: JSON file containing all format information (see references/format_config_schema.md for details)
Step 2: Prepare Content Data
Create a JSON file with the actual content for the new document. The content must follow the structure defined in references/content_data_schema.md.
Content Structure:
{
"metadata": {
"title": "Document Title",
"author": "Author Name",
"version": "1.0",
"date": "2025-01-15"
},
"sections": [
{
"type": "heading",
"content": "Section Title",
"level": 1,
"number": "1"
},
{
"type": "paragraph",
"content": "Paragraph text content."
},
{
"type": "table",
"rows": 3,
"cells": [
["Header 1", "Header 2"],
["Data 1", "Data 2"]
]
}
]
}Supported Section Types:
heading- Headings with optional numberingparagraph- Text paragraphstable- Tables with configurable rows and columnspage_break- Page breaks
See assets/example_content.json for a complete example.
Step 3: Generate New Document
Generate a new Word document using the extracted format and prepared content.
python scripts/generate_document.py <format.json> <content.json> <output.docx>Example:
python scripts/generate_document.py format_template.json new_content.json output_document.docxResult: A new .docx file with the format from the template applied to the new content.
Complete Example Workflow
User asks: "I have a research task document. I need to create 5 more documents with the same format but different content."
1. Extract the format:
python scripts/extract_format.py research_task_template.docx template_format.json2. Create content files for each new document (content1.json, content2.json, etc.)
3. Generate documents:
python scripts/generate_document.py template_format.json content1.json document1.docx
python scripts/generate_document.py template_format.json content2.json document2.docx
# ... repeat for all documentsCommon Use Cases
Corporate Document Templates
Extract format from a company template and generate reports, proposals, or specifications with consistent branding.
# One-time: Extract company template
python scripts/extract_format.py "Company Template.docx" company_format.json
# For each new document:
python scripts/generate_document.py company_format.json new_report.json "Monthly Report.docx"Technical Documentation Series
Create multiple technical documents (specifications, test plans, manuals) with identical formatting.
# Extract from specification template
python scripts/extract_format.py spec_template.docx spec_format.json
# Generate multiple specs
python scripts/generate_document.py spec_format.json product_a_spec.json "Product A Spec.docx"
python scripts/generate_document.py spec_format.json product_b_spec.json "Product B Spec.docx"Research Task Documents
The included example template (assets/hy_template_format.json) demonstrates a complete research task document format with:
- Approval/review table in header
- Multi-level numbering (1, 1.1, 1.1.1)
- Technical specification tables
- Structured sections
Use this as a starting point for similar technical documents.
Advanced Usage
Customizing Extraction
Modify scripts/extract_format.py to extract additional properties not covered by default:
- Custom XML elements
- Advanced table features (merged cells, borders)
- Embedded objects
- Custom properties
Extending Content Types
Add new section types in scripts/generate_document.py:
- Images with captions
- Bulleted or numbered lists
- Footnotes and endnotes
- Custom content blocks
See references/content_data_schema.md for extension guidelines.
Batch Processing
Create a wrapper script to generate multiple documents:
import json
import subprocess
format_file = "template_format.json"
content_files = ["content1.json", "content2.json", "content3.json"]
for i, content_file in enumerate(content_files, 1):
output = f"document_{i}.docx"
subprocess.run([
"python", "scripts/generate_document.py",
format_file, content_file, output
])Dependencies
The scripts require:
- Python 3.7+
python-docxlibrary:pip install python-docx
No additional dependencies are needed for the core functionality.
Resources
scripts/
- extract_format.py - Extract formatting from Word documents
- generate_document.py - Generate new documents from format + content
Both scripts include built-in help:
python scripts/extract_format.py --help
python scripts/generate_document.py --helpreferences/
- format_config_schema.md - Complete schema for format configuration files
- content_data_schema.md - Complete schema for content data files
Read these for detailed information on file structures and available options.
assets/
- hy_template_format.json - Example extracted format from a technical research task document
- example_content.json - Example content data showing all section types
Use these as references when creating your own format and content files.
Troubleshooting
Missing styles in output: Ensure style IDs in content data match those in format config. Check format.json for available style IDs.
Table formatting issues: Verify table dimensions (rows/columns) match between content data and format config. See format_config_schema.md for table structure.
Font not displaying correctly: Some fonts may not be available on all systems. Check that referenced fonts are installed.
Dependencies missing: Install required Python packages:
pip install python-docxTips
1. Test with examples first: Use the included hy_template_format.json and example_content.json to understand the workflow before extracting your own formats.
2. Start simple: Begin with basic headings and paragraphs, then add tables and complex formatting.
3. Validate JSON: Use a JSON validator to check content data files before generating documents.
4. Keep format configs: Store extracted format configurations for reuse across multiple projects.
5. Version control: Track both format configs and content data in version control for reproducible document generation.
{
"metadata": {
"title": "Example Research Task Specification",
"author": "Research Team",
"version": "1.0",
"date": "2025-01-15"
},
"sections": [
{
"type": "heading",
"content": "引言",
"level": 1,
"number": "1"
},
{
"type": "paragraph",
"content": "本文档定义了示例产品的研制任务和技术要求。"
},
{
"type": "heading",
"content": "产品名称及代号",
"level": 1,
"number": "2"
},
{
"type": "paragraph",
"content": "产品名称:示例控制系统"
},
{
"type": "paragraph",
"content": "产品代号:EX-2025-001"
},
{
"type": "heading",
"content": "产品组成及功能",
"level": 1,
"number": "3"
},
{
"type": "heading",
"content": "产品组成",
"level": 2,
"number": "3.1"
},
{
"type": "paragraph",
"content": "本产品由以下部分组成:"
},
{
"type": "paragraph",
"content": "1. 主控单元\n2. 通信模块\n3. 电源模块\n4. 接口板"
},
{
"type": "heading",
"content": "功能要求",
"level": 2,
"number": "3.2"
},
{
"type": "paragraph",
"content": "系统应具备数据采集、处理和通信功能。"
},
{
"type": "heading",
"content": "技术指标要求",
"level": 1,
"number": "4"
},
{
"type": "heading",
"content": "电气要求",
"level": 2,
"number": "4.1"
},
{
"type": "heading",
"content": "电源要求",
"level": 3,
"number": "4.1.1"
},
{
"type": "table",
"rows": 4,
"columns": ["3000", "7000"],
"cells": [
["参数", "指标"],
["输入电压", "220V AC ± 10%"],
["功耗", "≤ 500W"],
["频率", "50Hz ± 2Hz"]
]
},
{
"type": "heading",
"content": "使用要求",
"level": 1,
"number": "5"
},
{
"type": "heading",
"content": "质量要求",
"level": 2,
"number": "5.1"
},
{
"type": "paragraph",
"content": "产品应符合相关质量标准,通过所有必要的测试和验证。"
},
{
"type": "heading",
"content": "环境要求",
"level": 2,
"number": "5.2"
},
{
"type": "paragraph",
"content": "工作温度:-20°C ~ +55°C\n储存温度:-40°C ~ +70°C\n相对湿度:≤95%(无凝露)"
}
]
}
Content Data Schema
This document describes the JSON schema for content data files used by generate_document.py.
Overview
The content data file defines the actual content (text, headings, tables) that will be placed into a Word document using the formatting rules from a format configuration.
Schema Structure
{
"metadata": {},
"sections": []
}Fields
metadata
Type: object Description: Optional metadata about the document content.
Fields:
title(string): Document titleauthor(string): Document authorversion(string): Version numberdate(string): Document date
Example:
"metadata": {
"title": "Product Research Task Specification",
"author": "Engineering Team",
"version": "1.0",
"date": "2025-01-15"
}sections
Type: array Description: Array of content sections that make up the document. Sections are processed in order.
Each section is an object with a type field and type-specific properties.
Section Types
Heading Section
Create a heading with optional numbering.
Fields:
type(string): Must be"heading"content(string): Heading textlevel(number): Heading level (1-9)number(string, optional): Numbering prefix (e.g., "1", "1.1", "1.1.1")
Example:
{
"type": "heading",
"content": "Introduction",
"level": 1,
"number": "1"
}Paragraph Section
Create a text paragraph.
Fields:
type(string): Must be"paragraph"content(string): Paragraph textstyle_id(string, optional): Style ID to apply from format config
Example:
{
"type": "paragraph",
"content": "This document outlines the technical requirements for the product.",
"style_id": "1"
}Table Section
Create a table.
Fields:
type(string): Must be"table"rows(number): Number of rowscolumns(array): Column width definitions (from format config)table_index(number, optional): Index of table config to usecells(array): 2D array of cell contents
Example:
{
"type": "table",
"rows": 3,
"columns": ["2000", "8000"],
"table_index": 0,
"cells": [
["Header 1", "Header 2"],
["Row 1 Col 1", "Row 1 Col 2"],
["Row 2 Col 1", "Row 2 Col 2"]
]
}Page Break Section
Insert a page break.
Fields:
type(string): Must be"page_break"
Example:
{
"type": "page_break"
}Complete Example
Here's a complete content data file for a technical document:
{
"metadata": {
"title": "New Product Research Task Specification",
"author": "Research Team",
"version": "1.0",
"date": "2025-01-15"
},
"sections": [
{
"type": "heading",
"content": "Introduction",
"level": 1,
"number": "1"
},
{
"type": "paragraph",
"content": "This document defines the research and development tasks for the new product initiative."
},
{
"type": "heading",
"content": "Product Name and Code",
"level": 1,
"number": "2"
},
{
"type": "paragraph",
"content": "Product Name: Advanced Control System"
},
{
"type": "paragraph",
"content": "Product Code: ACS-2025-01"
},
{
"type": "heading",
"content": "Technical Specifications",
"level": 1,
"number": "3"
},
{
"type": "heading",
"content": "Electrical Requirements",
"level": 2,
"number": "3.1"
},
{
"type": "table",
"rows": 4,
"columns": ["3000", "7000"],
"cells": [
["Parameter", "Specification"],
["Input Voltage", "220V AC ± 10%"],
["Power Consumption", "≤ 500W"],
["Frequency", "50Hz ± 2Hz"]
]
},
{
"type": "page_break"
},
{
"type": "heading",
"content": "Testing Requirements",
"level": 1,
"number": "4"
},
{
"type": "paragraph",
"content": "All products must undergo comprehensive testing according to industry standards."
}
]
}Usage Patterns
Multi-level Numbering
For documents with nested sections (1, 1.1, 1.1.1):
[
{"type": "heading", "content": "First Section", "level": 1, "number": "1"},
{"type": "heading", "content": "Subsection A", "level": 2, "number": "1.1"},
{"type": "heading", "content": "Sub-subsection", "level": 3, "number": "1.1.1"},
{"type": "heading", "content": "Subsection B", "level": 2, "number": "1.2"},
{"type": "heading", "content": "Second Section", "level": 1, "number": "2"}
]Complex Tables
For tables with merged cells or special formatting, you may need to extend the schema:
{
"type": "table",
"rows": 3,
"columns": ["2000", "4000", "4000"],
"cells": [
["Header 1", "Header 2", "Header 3"],
["Data 1", "Data 2", "Data 3"],
["Data 4", "Data 5", "Data 6"]
],
"merge_cells": [
{"row": 0, "col": 1, "row_span": 1, "col_span": 2}
]
}Approval Tables
For documents with approval/review tables (common in technical documents):
{
"type": "table",
"table_index": 0,
"cells": [
["Version", "1.0"],
["Author", "John Doe"],
["Reviewer", "Jane Smith"],
["Approver", "Manager Name"],
["Date", "2025-01-15"]
]
}Tips
1. Consistent Numbering: Ensure numbering is sequential and follows the document hierarchy 2. Style IDs: Reference style IDs from the format configuration to maintain consistency 3. Table Index: Use the same table_index for tables that should have the same formatting 4. Empty Paragraphs: Use empty content strings for spacing: {"type": "paragraph", "content": ""} 5. Special Characters: Properly escape JSON special characters in content strings
Extending the Schema
To support additional content types:
1. Define a new section type 2. Add handling in generate_document.py 3. Document the new type in this file 4. Provide examples
Common extensions:
- Images (
{"type": "image", "path": "...", "width": "..."}) - Lists (
{"type": "list", "items": [...], "style": "bullet"}) - Footnotes (
{"type": "footnote", "content": "..."})
Format Configuration Schema
This document describes the JSON schema for format configuration files generated by extract_format.py.
Overview
The format configuration file stores extracted formatting information from a Word document, including styles, numbering, table structures, and header/footer information.
Schema Structure
{
"source_document": "string",
"styles": {},
"numbering": {},
"tables": [],
"headers_footers": {}
}Fields
source_document
Type: string Description: Name of the source document from which the format was extracted.
Example:
"source_document": "template.docx"styles
Type: object Description: Dictionary of style definitions, keyed by style ID.
Each style object contains:
id(string): Style identifiername(string): Human-readable style nametype(string): Style type (paragraph, character, table, numbering)fonts(object): Font propertiesascii(string): ASCII font namehAnsi(string): High ANSI font nameeastAsia(string): East Asian font namesize(string): Font size in half-pointsparagraph(object): Paragraph propertiesalignment(string): Text alignment (left, center, right, both)spacing(object): Line spacing configuration
Example:
"styles": {
"1": {
"id": "1",
"name": "Normal",
"type": "paragraph",
"fonts": {
"ascii": "Times New Roman",
"hAnsi": "Times New Roman",
"eastAsia": "宋体",
"size": "24"
},
"paragraph": {
"alignment": "left",
"spacing": {
"line": "360",
"lineRule": "auto"
}
}
},
"2": {
"id": "2",
"name": "heading 1",
"type": "paragraph",
"fonts": {
"ascii": "Times New Roman",
"size": "32"
},
"paragraph": {
"alignment": "left"
}
}
}numbering
Type: object Description: Numbering definitions for automatic numbering (1, 1.1, 1.1.1, etc.)
Each numbering entry maps a numbering ID to its abstract numbering definition.
Example:
"numbering": {
"1": {
"abstractNumId": "0"
},
"2": {
"abstractNumId": "1"
}
}tables
Type: array Description: Array of table structure definitions found in the document.
Each table object contains:
index(number): Zero-based index of the tablerows(number): Number of rows in the tablecolumns(array): Array of column widthsproperties(object): Table propertieswidth(object): Table width settingsstyle(string): Table style ID
Example:
"tables": [
{
"index": 0,
"rows": 5,
"columns": ["1984", "8076", "40"],
"properties": {
"width": {
"value": "10100",
"type": "dxa"
},
"style": "49"
}
}
]headers_footers
Type: object Description: Information about headers and footers in the document.
Contains:
headers(array): List of header filesfooters(array): List of footer files
Example:
"headers_footers": {
"headers": [
{
"file": "word/header1.xml",
"exists": true
}
],
"footers": [
{
"file": "word/footer1.xml",
"exists": true
}
]
}Usage Notes
Style IDs vs Style Names
Word documents use numeric style IDs internally (e.g., "1", "2") which map to named styles (e.g., "Normal", "heading 1"). The format configuration preserves both for maximum compatibility.
Width Units
Widths in OOXML use "dxa" units (twentieths of a point). Common conversions:
- 1 inch = 1440 dxa
- 1 cm = 567 dxa
- 1 pt = 20 dxa
Extracting Additional Properties
The current schema covers the most common formatting properties. For specialized documents, you may need to:
1. Modify extract_format.py to extract additional properties 2. Update this schema documentation accordingly 3. Update generate_document.py to apply those properties
Example Complete Configuration
{
"source_document": "research_task_template.docx",
"styles": {
"1": {
"id": "1",
"name": "Normal",
"type": "paragraph",
"fonts": {
"ascii": "Times New Roman",
"hAnsi": "Times New Roman",
"eastAsia": "宋体",
"size": "24"
},
"paragraph": {
"alignment": "left"
}
}
},
"numbering": {
"1": {
"abstractNumId": "0"
}
},
"tables": [
{
"index": 0,
"rows": 8,
"columns": ["2000", "8000"],
"properties": {
"width": {
"value": "10000",
"type": "dxa"
},
"style": "GridTable"
}
}
],
"headers_footers": {
"headers": [
{"file": "word/header1.xml", "exists": true}
],
"footers": [
{"file": "word/footer1.xml", "exists": true}
]
}
}#!/usr/bin/env python3
"""
Extract format information from a Word document (.docx).
This script analyzes the OOXML structure and extracts reusable format information.
"""
import sys
import json
import zipfile
from pathlib import Path
from xml.etree import ElementTree as ET
from collections import defaultdict
# OOXML namespaces
NAMESPACES = {
'w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
'r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
'a': 'http://schemas.openxmlformats.org/drawingml/2006/main',
'wp': 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing',
}
def extract_styles(styles_xml):
"""Extract style definitions from styles.xml"""
tree = ET.parse(styles_xml)
root = tree.getroot()
styles = {}
for style in root.findall('.//w:style', NAMESPACES):
style_id = style.get(f"{{{NAMESPACES['w']}}}styleId")
style_type = style.get(f"{{{NAMESPACES['w']}}}type")
name_elem = style.find('w:name', NAMESPACES)
style_name = name_elem.get(f"{{{NAMESPACES['w']}}}val") if name_elem is not None else None
# Extract font info
rpr = style.find('.//w:rPr', NAMESPACES)
fonts = {}
if rpr is not None:
font_elem = rpr.find('w:rFonts', NAMESPACES)
if font_elem is not None:
fonts = {
'ascii': font_elem.get(f"{{{NAMESPACES['w']}}}ascii"),
'hAnsi': font_elem.get(f"{{{NAMESPACES['w']}}}hAnsi"),
'eastAsia': font_elem.get(f"{{{NAMESPACES['w']}}}eastAsia"),
}
# Font size
sz_elem = rpr.find('w:sz', NAMESPACES)
if sz_elem is not None:
fonts['size'] = sz_elem.get(f"{{{NAMESPACES['w']}}}val")
# Extract paragraph properties
ppr = style.find('.//w:pPr', NAMESPACES)
para_props = {}
if ppr is not None:
jc_elem = ppr.find('w:jc', NAMESPACES)
if jc_elem is not None:
para_props['alignment'] = jc_elem.get(f"{{{NAMESPACES['w']}}}val")
spacing_elem = ppr.find('w:spacing', NAMESPACES)
if spacing_elem is not None:
para_props['spacing'] = {
'line': spacing_elem.get(f"{{{NAMESPACES['w']}}}line"),
'lineRule': spacing_elem.get(f"{{{NAMESPACES['w']}}}lineRule"),
}
styles[style_id] = {
'id': style_id,
'name': style_name,
'type': style_type,
'fonts': fonts,
'paragraph': para_props,
}
return styles
def extract_numbering(numbering_xml):
"""Extract numbering definitions from numbering.xml"""
if not numbering_xml.exists():
return {}
tree = ET.parse(numbering_xml)
root = tree.getroot()
numbering = {}
for num in root.findall('.//w:num', NAMESPACES):
num_id = num.get(f"{{{NAMESPACES['w']}}}numId")
abstract_num_id = num.find('w:abstractNumId', NAMESPACES)
if abstract_num_id is not None:
numbering[num_id] = {
'abstractNumId': abstract_num_id.get(f"{{{NAMESPACES['w']}}}val")
}
return numbering
def extract_table_structure(doc_xml):
"""Extract table structure from document.xml"""
tree = ET.parse(doc_xml)
root = tree.getroot()
tables = []
for idx, tbl in enumerate(root.findall('.//w:tbl', NAMESPACES)):
tbl_pr = tbl.find('w:tblPr', NAMESPACES)
table_info = {
'index': idx,
'rows': len(tbl.findall('w:tr', NAMESPACES)),
'properties': {}
}
if tbl_pr is not None:
# Table width
tbl_w = tbl_pr.find('w:tblW', NAMESPACES)
if tbl_w is not None:
table_info['properties']['width'] = {
'value': tbl_w.get(f"{{{NAMESPACES['w']}}}w"),
'type': tbl_w.get(f"{{{NAMESPACES['w']}}}type"),
}
# Table style
tbl_style = tbl_pr.find('w:tblStyle', NAMESPACES)
if tbl_style is not None:
table_info['properties']['style'] = tbl_style.get(f"{{{NAMESPACES['w']}}}val")
# Extract grid columns
grid = tbl.find('w:tblGrid', NAMESPACES)
if grid is not None:
cols = grid.findall('w:gridCol', NAMESPACES)
table_info['columns'] = [
col.get(f"{{{NAMESPACES['w']}}}w") for col in cols
]
tables.append(table_info)
return tables
def extract_headers_footers(docx_path):
"""Extract header and footer information"""
headers = []
footers = []
with zipfile.ZipFile(docx_path, 'r') as zf:
for name in zf.namelist():
if name.startswith('word/header'):
headers.append({
'file': name,
'exists': True
})
elif name.startswith('word/footer'):
footers.append({
'file': name,
'exists': True
})
return {'headers': headers, 'footers': footers}
def extract_format(docx_path, output_path):
"""Main function to extract format from a docx file"""
docx_path = Path(docx_path)
output_path = Path(output_path)
if not docx_path.exists():
print(f"Error: File not found: {docx_path}")
return 1
# Create temporary directory to unpack docx
import tempfile
import shutil
with tempfile.TemporaryDirectory() as tmpdir:
tmpdir = Path(tmpdir)
# Unpack docx
with zipfile.ZipFile(docx_path, 'r') as zf:
zf.extractall(tmpdir)
word_dir = tmpdir / 'word'
# Extract various format components
format_info = {
'source_document': str(docx_path.name),
'styles': {},
'numbering': {},
'tables': [],
'headers_footers': {}
}
# Extract styles
styles_path = word_dir / 'styles.xml'
if styles_path.exists():
format_info['styles'] = extract_styles(styles_path)
# Extract numbering
numbering_path = word_dir / 'numbering.xml'
if numbering_path.exists():
format_info['numbering'] = extract_numbering(numbering_path)
# Extract table structures
doc_path = word_dir / 'document.xml'
if doc_path.exists():
format_info['tables'] = extract_table_structure(doc_path)
# Extract headers/footers info
format_info['headers_footers'] = extract_headers_footers(docx_path)
# Save to output file
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(format_info, f, indent=2, ensure_ascii=False)
print(f"✅ Format extracted successfully!")
print(f" Source: {docx_path}")
print(f" Output: {output_path}")
print(f"\nExtracted:")
print(f" - {len(format_info['styles'])} styles")
print(f" - {len(format_info['numbering'])} numbering definitions")
print(f" - {len(format_info['tables'])} tables")
print(f" - {len(format_info['headers_footers']['headers'])} headers")
print(f" - {len(format_info['headers_footers']['footers'])} footers")
return 0
def main():
if len(sys.argv) < 2:
print("Usage: extract_format.py <input.docx> [output.json]")
print("\nExtract format information from a Word document.")
print("\nArguments:")
print(" input.docx - Path to the Word document to analyze")
print(" output.json - Path for output JSON file (default: format.json)")
return 1
input_path = sys.argv[1]
output_path = sys.argv[2] if len(sys.argv) > 2 else "format.json"
return extract_format(input_path, output_path)
if __name__ == '__main__':
sys.exit(main())
#!/usr/bin/env python3
"""
Generate a Word document using extracted format information and content data.
"""
import sys
import json
from pathlib import Path
from docx import Document
from docx.shared import Pt, RGBColor, Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
def apply_style_from_config(paragraph, style_config):
"""Apply style configuration to a paragraph"""
if not style_config:
return
# Apply fonts
fonts = style_config.get('fonts', {})
if fonts:
for run in paragraph.runs:
if 'ascii' in fonts and fonts['ascii']:
run.font.name = fonts['ascii']
if 'size' in fonts and fonts['size']:
# Size is in half-points, convert to points
run.font.size = Pt(int(fonts['size']) / 2)
# Apply paragraph alignment
para_props = style_config.get('paragraph', {})
if para_props:
alignment = para_props.get('alignment')
if alignment == 'center':
paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
elif alignment == 'right':
paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT
elif alignment == 'left':
paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT
elif alignment == 'both':
paragraph.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY
def add_heading_with_number(doc, text, level, number_text=None):
"""Add a heading with optional numbering"""
heading = doc.add_heading(text, level=level)
if number_text:
# Prepend number to heading text
heading.text = f"{number_text} {text}"
return heading
def add_table_from_structure(doc, table_data, table_config):
"""Add a table based on configuration"""
rows = table_data.get('rows', 1)
cols = len(table_data.get('columns', [1]))
table = doc.add_table(rows=rows, cols=cols)
# Apply table style if available
table_props = table_config.get('properties', {})
style = table_props.get('style')
if style:
# python-docx uses style names, not IDs
# You may need to map style IDs to names
pass
# Fill table with data if provided
if 'cells' in table_data:
for row_idx, row_data in enumerate(table_data['cells']):
if row_idx < len(table.rows):
for col_idx, cell_text in enumerate(row_data):
if col_idx < len(table.columns):
table.rows[row_idx].cells[col_idx].text = str(cell_text)
return table
def generate_document(format_path, content_path, output_path):
"""Generate a document from format and content configurations"""
format_path = Path(format_path)
content_path = Path(content_path)
output_path = Path(output_path)
if not format_path.exists():
print(f"Error: Format file not found: {format_path}")
return 1
if not content_path.exists():
print(f"Error: Content file not found: {content_path}")
return 1
# Load configurations
with open(format_path, 'r', encoding='utf-8') as f:
format_config = json.load(f)
with open(content_path, 'r', encoding='utf-8') as f:
content_data = json.load(f)
# Create document
doc = Document()
# Set default style if available
styles = format_config.get('styles', {})
default_style = styles.get('1') # Style ID 1 is typically "Normal"
# Process content sections
sections = content_data.get('sections', [])
for section in sections:
section_type = section.get('type')
section_content = section.get('content', '')
level = section.get('level', 1)
number = section.get('number')
if section_type == 'heading':
add_heading_with_number(doc, section_content, level, number)
elif section_type == 'paragraph':
para = doc.add_paragraph(section_content)
style_id = section.get('style_id')
if style_id and style_id in styles:
apply_style_from_config(para, styles[style_id])
elif section_type == 'table':
table_idx = section.get('table_index', 0)
table_configs = format_config.get('tables', [])
table_config = table_configs[table_idx] if table_idx < len(table_configs) else {}
add_table_from_structure(doc, section, table_config)
elif section_type == 'page_break':
doc.add_page_break()
# Save document
doc.save(str(output_path))
print(f"✅ Document generated successfully!")
print(f" Format: {format_path.name}")
print(f" Content: {content_path.name}")
print(f" Output: {output_path}")
print(f"\nGenerated:")
print(f" - {len(sections)} sections")
return 0
def main():
if len(sys.argv) < 3:
print("Usage: generate_document.py <format.json> <content.json> <output.docx>")
print("\nGenerate a Word document from format and content configurations.")
print("\nArguments:")
print(" format.json - Path to extracted format configuration")
print(" content.json - Path to content data file")
print(" output.docx - Path for output Word document")
return 1
format_path = sys.argv[1]
content_path = sys.argv[2]
output_path = sys.argv[3] if len(sys.argv) > 3 else "output.docx"
return generate_document(format_path, content_path, output_path)
if __name__ == '__main__':
sys.exit(main())
Related skills
How it compares
Pick docx-format-replicator for Word style cloning; use Markdown or PDF generator skills for non-.docx document pipelines.
FAQ
What file format does docx-format-replicator work with?
docx-format-replicator works with Word .docx files at version 1.0.0. The skill extracts formatting including fonts, headings, and layout from a reference document and applies it to new content in generated files.
When should developers use docx-format-replicator?
docx-format-replicator suits developers creating multiple documents with consistent formatting, replicating corporate templates, or maintaining document standards across different content without manual Word styling.