SuperAPI AI Directory

hwpx

General & other

View repository

Updated 10-16 03:16

About this skill

HWPX Document Skill — XML-first Workflow

Hangul (Hancom Office) HWPX files Writing XML directly -centered skill for creating, editing, and reading. HWPX is a ZIP-based XML container (OWPML standard). It completely bypasses the formatting bugs of the python-hwpx API and enables fine-grained formatting control.

Environment

# SKILL_DIR는 이 SKILL.md가 위치한 디렉토리의 절대 경로로 설정
SKILL_DIR="$(cd "$(dirname "$0")/.." && pwd)"   # 스크립트 내에서
# 또는 Claude Code가 자동으로 주입하는 base directory 경로를 사용

# Python 가상환경 (프로젝트에 맞게 설정)
VENV="<프로젝트>/.venv/bin/activate"

For all Python executions:

# 프로젝트의 .venv를 활성화 (pip install lxml 필요)
source "$VENV"

Directory Structure

.claude/skills/hwpx/
├── SKILL.md                              # 이 파일
├── scripts/
│   ├── office/
│   │   ├── unpack.py                     # HWPX → 디렉토리 (XML pretty-print)
│   │   └── pack.py                       # 디렉토리 → HWPX
│   ├── build_hwpx.py                     # 템플릿 + XML → .hwpx 조립 (핵심)
│   ├── analyze_template.py               # HWPX 심층 분석 (레퍼런스 기반 생성용)
│   ├── validate.py                       # HWPX 구조 검증
│   └── text_extract.py                   # 텍스트 추출
├── templates/
│   ├── base/                             # 베이스 템플릿 (Skeleton 기반)
│   │   ├── mimetype, META-INF/*, version.xml, settings.xml, Preview/*
│   │   └── Contents/ (header.xml, section0.xml, content.hpf)
│   ├── gonmun/                           # 공문 오버레이 (header.xml, section0.xml)
│   ├── report/                           # 보고서 오버레이
│   ├── minutes/                          # 회의록 오버레이
│   └── proposal/                         # 제안서/사업개요 오버레이 (색상 헤더바, 번호 배지)
├── examples/
│   ├── 01_basic_document.sh              # XML로 기본 문서 빌드
│   ├── 02_gonmun_example.sh              # 공문 템플릿 사용
│   ├── 03_report_with_table.sh           # 표 포함 보고서
│   ├── 04_read_and_extract.py            # 기존 문서 읽기/추출
│   ├── 05_edit_existing.sh               # unpack→편집→pack
│   ├── sample_section0.xml               # 주석 달린 section0 예제
│   └── sample_header.xml                 # 주석 달린 header 예제
└── references/
    └── hwpx-format.md                    # OWPML XML 요소 레퍼런스

Workflow 1: XML-first Document Creation (Main Workflow)

Flow

  1. Select Template (base/gonmun/report/minutes/proposal)
  2. Write section0.xml (body content)
  3. (Optional) Modify header.xml (when new styles need to be added)
  4. Build with build_hwpx.py
  5. Validate with validate.py

Basic Usage

source "$VENV"

# 빈 문서 (base 템플릿)
python3 "$SKILL_DIR/scripts/build_hwpx.py" --output result.hwpx

# 템플릿 사용
python3 "$SKILL_DIR/scripts/build_hwpx.py" --template gonmun --output result.hwpx

# 커스텀 section0.xml 오버라이드
python3 "$SKILL_DIR/scripts/build_hwpx.py" --template gonmun --section my_section0.xml --output result.hwpx

# header도 오버라이드
python3 "$SKILL_DIR/scripts/build_hwpx.py" --header my_header.xml --section my_section0.xml --output result.hwpx

# 메타데이터 설정
python3 "$SKILL_DIR/scripts/build_hwpx.py" --template report --section my.xml \
  --title "제목" --creator "작성자" --output result.hwpx

Practical Pattern: Write section0.xml Inline → Build

# 1. section0.xml을 임시파일로 작성
SECTION=$(mktemp /tmp/section0_XXXX.xml)
cat > "$SECTION" << 'XMLEOF'
<?xml version='1.0' encoding='UTF-8'?>
<hs:sec xmlns:hp="http://www.hancom.co.kr/hwpml/2011/paragraph"
        xmlns:hs="http://www.hancom.co.kr/hwpml/2011/section">
  <!-- secPr 포함 첫 문단 (base/section0.xml에서 복사) -->
  <!-- ... -->
  <hp:p id="1000000002" paraPrIDRef="0" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0">
    <hp:run charPrIDRef="0">
      <hp:t>본문 내용</hp:t>
    </hp:run>
  </hp:p>
</hs:sec>
XMLEOF

# 2. 빌드
python3 "$SKILL_DIR/scripts/build_hwpx.py" --section "$SECTION" --output result.hwpx

# 3. 정리
rm -f "$SECTION"

section0.xml Writing Guide

Required Structure

The first paragraph of section0.xml (<hp:p>)의 첫 런(<hp:run>) must <hp:secPr>과 <hp:colPr> include:

<hp:p id="1000000001" paraPrIDRef="0" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0">
  <hp:run charPrIDRef="0">
    <hp:secPr ...>
      <!-- 페이지 크기, 여백, 각주/미주 설정 등 -->
    </hp:secPr>
    <hp:ctrl>
      <hp:colPr id="" type="NEWSPAPER" layout="LEFT" colCount="1" sameSz="1" sameGap="0"/>
    </hp:ctrl>
  </hp:run>
  <hp:run charPrIDRef="0"><hp:t/></hp:run>
</hp:p>

Tip: templates/base/Contents/section0.xml You can simply copy the first paragraph of .

Paragraph

<hp:p id="고유ID" paraPrIDRef="문단스타일ID" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0">
  <hp:run charPrIDRef="글자스타일ID">
    <hp:t>텍스트 내용</hp:t>
  </hp:run>
</hp:p>

빈 줄

<hp:p id="고유ID" paraPrIDRef="0" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0">
  <hp:run charPrIDRef="0"><hp:t/></hp:run>
</hp:p>

Mixed-formatting run (multiple styles in one paragraph)

<hp:p id="고유ID" paraPrIDRef="0" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0">
  <hp:run charPrIDRef="0"><hp:t>일반 텍스트 </hp:t></hp:run>
  <hp:run charPrIDRef="7"><hp:t>볼드 텍스트</hp:t></hp:run>
  <hp:run charPrIDRef="0"><hp:t> 다시 일반</hp:t></hp:run>
</hp:p>

How to Create Tables

<hp:p id="고유ID" paraPrIDRef="0" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0">
  <hp:run charPrIDRef="0">
    <hp:tbl id="고유ID" zOrder="0" numberingType="TABLE" textWrap="TOP_AND_BOTTOM"
            textFlow="BOTH_SIDES" lock="0" dropcapstyle="None" pageBreak="CELL"
            repeatHeader="0" rowCnt="행수" colCnt="열수" cellSpacing="0"
            borderFillIDRef="3" noAdjust="0">
      <hp:sz width="42520" widthRelTo="ABSOLUTE" height="전체높이" heightRelTo="ABSOLUTE" protect="0"/>
      <hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="1" allowOverlap="0"
              holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="COLUMN" vertAlign="TOP"
              horzAlign="LEFT" vertOffset="0" horzOffset="0"/>
      <hp:outMargin left="0" right="0" top="0" bottom="0"/>
      <hp:inMargin left="0" right="0" top="0" bottom="0"/>
      <hp:tr>
        <hp:tc name="" header="0" hasMargin="0" protect="0" editable="0" dirty="1" borderFillIDRef="4">
          <hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="CENTER"
                     linkListIDRef="0" linkListNextIDRef="0" textWidth="0" textHeight="0"
                     hasTextRef="0" hasNumRef="0">
            <hp:p paraPrIDRef="21" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0" id="고유ID">
              <hp:run charPrIDRef="9"><hp:t>헤더 셀</hp:t></hp:run>
            </hp:p>
          </hp:subList>
          <hp:cellAddr colAddr="0" rowAddr="0"/>
          <hp:cellSpan colSpan="1" rowSpan="1"/>
          <hp:cellSz width="열너비" height="행높이"/>
          <hp:cellMargin left="0" right="0" top="0" bottom="0"/>
        </hp:tc>
        <!-- 나머지 셀... -->
      </hp:tr>
    </hp:tbl>
  </hp:run>
</hp:p>

Table Size Calculation

  • A4 body width: 42520 HWPUNIT = 59528 (paper) - 8504×2 (left/right margins)
  • Sum of column widths = body width (42520)
  • Example: 3 equal columns → 14173 + 14173 + 14174 = 42520
  • Example: 2 columns (label:content = 1:4) → 8504 + 34016 = 42520
  • Row height: usually 2400~3600 HWPUNIT per cell

ID Rules

  • Paragraph id: 1000000001increment sequentially from
  • 표 id: 1000000099 It is recommended to use separate ranges such as
  • All ids must be unique within the document

header.xml Modification Guide

How to Add Custom Styles

  1. templates/base/Contents/header.xml Copy
  2. Add the necessary charPr/paraPr/borderFill
  3. For each group, itemCnt update the attribute

Example of adding charPr (bold 14pt)

<hh:charPr id="8" height="1400" textColor="#000000" shadeColor="none"
           useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="2">
  <hh:fontRef hangul="1" latin="1" hanja="1" japanese="1" other="1" symbol="1" user="1"/>
  <hh:ratio hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
  <hh:spacing hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
  <hh:relSz hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
  <hh:offset hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
  <hh:bold/>
  <hh:underline type="NONE" shape="SOLID" color="#000000"/>
  <hh:strikeout shape="NONE" color="#000000"/>
  <hh:outline type="NONE"/>
  <hh:shadow type="NONE" color="#C0C0C0" offsetX="10" offsetY="10"/>
</hh:charPr>

Font Reference System

  • fontRef The value is fontfacesthe font id defined in
  • hangul="0" → Hamchorom Dotum (Gothic)
  • hangul="1" → Hamchorom Batang (Myeongjo)
  • Set all 7 languages identically

Cautions When Adding paraPr

  • Must hp:switch include the structure (hp:case + hp:default)
  • hp:case와 hp:defaultThe values of are usually the same (or default is 2x)
  • borderFillIDRef="2" maintain

Style ID Map per Template

base (default)

ID Type Description
charPr 0 Character 10pt Hamchorom Batang, default
charPr 1 Character 10pt Hamchorom Dotum
charPr 2~6 Character Skeleton default style
paraPr 0 Paragraph JUSTIFY, 160% line spacing
paraPr 1~19 Paragraph Skeleton default (outline, footnotes, etc.)
borderFill 1 Border None (page border)
borderFill 2 Border None + transparent background (for reference)

gonmun (official document) — base + additions

ID Type Description
charPr 7 Text 22pt bold Hamchoreum Batang (institution name/title)
charPr 8 Text 16pt bold Hamchoreum Batang (signer)
charPr 9 Text 8pt Hamchoreum Batang (bottom contact info)
charPr 10 Text 10pt bold Hamchoreum Batang (table header)
paraPr 20 Paragraph CENTER, 160% line spacing
paraPr 21 Paragraph CENTER, 130% (표 셀)
paraPr 22 Paragraph JUSTIFY, 130% (표 셀)
borderFill 3 Border SOLID 0.12mm 4면
borderFill 4 Border SOLID 0.12mm + #D6DCE4 background

report — base + additions

ID Type Description
charPr 7 Text 20pt bold (document title)
charPr 8 Text 14pt bold (subheading)
charPr 9 Text 10pt bold (table header)
charPr 10 Text 10pt bold + underline (emphasized text)
charPr 11 Text 9pt Hamchoreum Batang (small/footnote)
charPr 12 Text 16pt bold Hamchoreum Batang (single-line title)
charPr 13 Text 12pt bold Hamchoreum Dotum (section header)
paraPr 20~22 Paragraph CENTER/JUSTIFY variants
paraPr 23 Paragraph RIGHT alignment, 160% line spacing
paraPr 24 Paragraph JUSTIFY, left 600 (□ checklist item indent)
paraPr 25 Paragraph JUSTIFY, left 1200 (sub-item ①②③ indent)
paraPr 26 Paragraph JUSTIFY, left 1800 (deep sub-item - indent)
paraPr 27 Paragraph LEFT, top and bottom border lines (for section header), prev 400
borderFill 3 Border SOLID 0.12mm 4면
borderFill 4 Border SOLID 0.12mm + #DAEEF3 background
borderFill 5 Border Top 0.4mm thick line + bottom 0.12mm thin line (section header)

Indentation rules: Must use paraPr's left margin, not space characters. □ items use paraPr 24, sub-items ①②③ use paraPr 25, deep - items use paraPr 26.

Section header rules: paraPr 27 + charPr 13 combination. Paragraph border (borderFillIDRef="5") automatically displays top thick line + bottom thin line.

minutes — base + additions

ID Type Description
charPr 7 Text 18pt bold (title)
charPr 8 Text 12pt bold (section label)
charPr 9 Text 10pt bold (table header)
paraPr 20~22 Paragraph CENTER/JUSTIFY variants
borderFill 3 Border SOLID 0.12mm 4면
borderFill 4 Border SOLID 0.12mm + #E2EFDA background

proposal — base + additions

For official documents requiring visual distinction. Color background header bar and number badge implemented with a table-based layout.

ID Type Description
charPr 7 Text 20pt bold HamchoRomBatang (document title)
charPr 8 Text 14pt bold HamchoRomBatang (subheading)
charPr 9 Text 10pt bold HamchoRomBatang (table header)
charPr 10 Text 14pt bold white HamchoRomDotum (major item number, green background)
charPr 11 Text 11pt bold white HamchoRomDotum (minor item number, blue background)
paraPr 20 Paragraph CENTER, 160% line spacing
paraPr 21 Paragraph CENTER, 130% (표 셀)
paraPr 22 Paragraph JUSTIFY, 130% (표 셀)
borderFill 3 Border SOLID 0.12mm 4면
borderFill 4 Border SOLID 0.12mm + #DAEEF3 background
borderFill 5 Border Olive green background #7B8B3D (major item number cell)
borderFill 6 Border Light gray background #F2F2F2 + gray border (major item title cell)
borderFill 7 Border Blue background #4472C4 (minor item number badge)
borderFill 8 Border Bottom border only #D0D0D0 (minor item title area)

proposal layout pattern

Major item header (2-cell table: number + title):

<!-- borderFillIDRef="5" + charPrIDRef="10" → 녹색배경 흰색 로마숫자 -->
<!-- borderFillIDRef="6" + charPrIDRef="8"  → 회색배경 검정 볼드 제목 -->

Minor item header (2-cell table: number badge + title):

<!-- borderFillIDRef="7" + charPrIDRef="11" → 파란배경 흰색 아라비아숫자 -->
<!-- borderFillIDRef="8" + charPrIDRef="8"  → 하단선만 검정 볼드 제목 -->

Workflow 2: Editing an existing document (unpack → Edit → pack)

source "$VENV"

# 1. HWPX → 디렉토리 (XML pretty-print)
python3 "$SKILL_DIR/scripts/office/unpack.py" document.hwpx ./unpacked/

# 2. XML 직접 편집 (Claude가 Read/Edit 도구로)
#    본문: ./unpacked/Contents/section0.xml
#    스타일: ./unpacked/Contents/header.xml

# 3. 다시 HWPX로 패키징
python3 "$SKILL_DIR/scripts/office/pack.py" ./unpacked/ edited.hwpx

# 4. 검증
python3 "$SKILL_DIR/scripts/validate.py" edited.hwpx

Workflow 3: Reading/text extraction

source "$VENV"

# 순수 텍스트
python3 "$SKILL_DIR/scripts/text_extract.py" document.hwpx

# 테이블 포함
python3 "$SKILL_DIR/scripts/text_extract.py" document.hwpx --include-tables

# 마크다운 형식
python3 "$SKILL_DIR/scripts/text_extract.py" document.hwpx --format markdown

Python API

from hwpx import TextExtractor
with TextExtractor("document.hwpx") as ext:
    text = ext.extract_text(include_nested=True, object_behavior="nested")
    print(text)

Workflow 4: Validation

source "$VENV"
python3 "$SKILL_DIR/scripts/validate.py" document.hwpx

Validation items: ZIP validity, required file existence, mimetype content/location/compression method, XML well-formedness


Workflow 5: Reference-based document generation

A workflow that analyzes a user-provided HWPX file and generates a document with the same layout.

Flow

  1. Analysis — analyze_template.pyfor in-depth analysis of the reference document
  2. Extract header.xml — use the reference's style definitions as-is
  3. Write section0.xml — write new content following the structure of the analysis results
  4. Build — build with the extracted header.xml + new section0.xml
  5. Validation

Usage

source "$VENV"

# 1. 심층 분석 (구조 청사진 출력)
python3 "$SKILL_DIR/scripts/analyze_template.py" reference.hwpx

# 2. header.xml과 section0.xml을 추출하여 참고용으로 보관
python3 "$SKILL_DIR/scripts/analyze_template.py" reference.hwpx \
  --extract-header /tmp/ref_header.xml \
  --extract-section /tmp/ref_section.xml

# 3. 분석 결과를 보고 새 section0.xml 작성
#    - 동일한 charPrIDRef, paraPrIDRef 사용
#    - 동일한 테이블 구조 (열 수, 열 너비, 행 수, rowSpan/colSpan)
#    - 동일한 borderFillIDRef, cellMargin

# 4. 추출한 header.xml + 새 section0.xml로 빌드
python3 "$SKILL_DIR/scripts/build_hwpx.py" \
  --header /tmp/ref_header.xml \
  --section /tmp/new_section0.xml \
  --output result.hwpx

# 5. 검증
python3 "$SKILL_DIR/scripts/validate.py" result.hwpx

Analysis output items

Item Description
Font definitions hangul/latin font mapping
borderFill Border type/thickness + background color (details per side)
charPr Font size (pt), font name, color, bold/italic/underline/strikethrough, fontRef
paraPr Alignment, line spacing, margins (left/right/prev/next/intent), heading, borderFillIDRef
Document structure Page size, margins, page border, body width
Body details id/paraPr/charPr of all paragraphs + text content
Table details rows×cols, column width array, per-cell span/margin/borderFill/vertAlign + content

Core Principles

  • Use charPrIDRef/paraPrIDRef as-is: Do not change the style IDs in the extracted header.xml
  • Sum of column widths = body width: Replicate the column width array from the analysis result exactly
  • Preserve rowSpan/colSpan patterns: Precisely reproduce the analyzed cell merge structure
  • Preserve cellMargin: Apply the analyzed cell margin values identically

Script Summary

Script Purpose
scripts/build_hwpx.py Key — Template + XML → HWPX assembly
scripts/analyze_template.py HWPX in-depth analysis (blueprint for reference-based generation)
scripts/office/unpack.py HWPX → directory (XML pretty-print)
scripts/office/pack.py Directory → HWPX (mimetype first)
scripts/validate.py Validate HWPX file structure
scripts/text_extract.py Extract HWPX text

Unit conversion

값 HWPUNIT Meaning
1pt 100 Base unit
10pt 1000 Base font size
1mm 283.5 Millimeter
1cm 2835 Centimeter
A4 폭 59528 210mm
A4 height 84186 297mm
Left/right margins 8504 30mm
Body width 42520 150mm (A4 - left/right margins)

Critical Rules

  1. Only HWPX is supported: .hwp(binary) files are not supported. If the user provides a .hwp file, in Hancom Office, .hwpxsave again asinstruct them to do so. (File → Save As → File type: HWPX)
  2. secPr required: The first run of the first paragraph in section0.xml must include secPr + colPr
  3. mimetype order: When packaging HWPX, mimetype must be the first ZIP entry, ZIP_STORED
  4. Preserve namespaces: When editing XML, hp:, hs:, hh:, hc: keep the prefix
  5. itemCnt consistency: The charProperties/paraProperties/borderFills itemCnt in header.xml must match the actual number of children
  6. ID reference consistency: The charPrIDRef/paraPrIDRef in section0.xml must match the definitions in header.xml
  7. Use venv: The project's .venv/bin/python3 (lxml package required)
  8. Validation: After generation, always validate.pyverify integrity with
  9. Reference: For detailed XML structure, see $SKILL_DIR/references/hwpx-format.md refer to
  10. build_hwpx.py first: Use build_hwpx.py for creating new documents (avoid calling the python-hwpx API directly)
  11. 빈 줄: <hp:t/> use (self-closing tag)