hwpx

📁 canine89/hwpxskill 📅 7 days ago
4
总安装量
4
周安装量
#52480
全站排名
安装命令
npx skills add https://github.com/canine89/hwpxskill --skill hwpx

Agent 安装分布

opencode 4
gemini-cli 4
github-copilot 4
codex 4
kimi-cli 4
amp 4

Skill 文档

HWPX 문서 스킬 — XML-first 워크플로우

한글(Hancom Office)의 HWPX 파일을 XML 직접 작성 중심으로 생성, 편집, 읽기할 수 있는 스킬. HWPX는 ZIP 기반 XML 컨테이너(OWPML 표준)이다. python-hwpx API의 서식 버그를 완전히 우회하며, 세밀한 서식 제어가 가능하다.

환경

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

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

모든 Python 실행 시:

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

디렉토리 구조

.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 요소 레퍼런스

워크플로우 1: XML-first 문서 생성 (주 워크플로우)

흐름

  1. 템플릿 선택 (base/gonmun/report/minutes/proposal)
  2. section0.xml 작성 (본문 내용)
  3. (선택) header.xml 수정 (새 스타일 추가 필요 시)
  4. build_hwpx.py로 빌드
  5. validate.py로 검증

기본 사용법

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

실전 패턴: section0.xml을 인라인 작성 → 빌드

# 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 작성 가이드

필수 구조

section0.xml의 첫 문단(<hp:p>)의 첫 런(<hp:run>)에 반드시 <hp:secPr>과 <hp:colPr> 포함:

<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 의 첫 문단을 그대로 복사하면 된다.

문단

<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>

서식 혼합 런 (한 문단에 여러 스타일)

<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>

표 작성법

<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>

표 크기 계산

  • A4 본문폭: 42520 HWPUNIT = 59528(용지) – 8504×2(좌우여백)
  • 열 너비 합 = 본문폭 (42520)
  • 예: 3열 균등 → 14173 + 14173 + 14174 = 42520
  • 예: 2열 (라벨:내용 = 1:4) → 8504 + 34016 = 42520
  • 행 높이: 셀당 보통 2400~3600 HWPUNIT

ID 규칙

  • 문단 id: 1000000001부터 순차 증가
  • 표 id: 1000000099 등 별도 범위 사용 권장
  • 모든 id는 문서 내 고유해야 함

header.xml 수정 가이드

커스텀 스타일 추가 방법

  1. templates/base/Contents/header.xml 복사
  2. 필요한 charPr/paraPr/borderFill 추가
  3. 각 그룹의 itemCnt 속성 업데이트

charPr 추가 예시 (볼드 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>

폰트 참조 체계

  • fontRef 값은 fontfaces에 정의된 font id
  • hangul="0" → 함초롬돋움 (고딕)
  • hangul="1" → 함초롬바탕 (명조)
  • 7개 언어 모두 동일하게 설정

paraPr 추가 시 주의

  • 반드시 hp:switch 구조 포함 (hp:case + hp:default)
  • hp:case와 hp:default의 값은 보통 동일 (또는 default가 2ë°°)
  • borderFillIDRef="2" 유지

템플릿별 스타일 ID 맵

base (기본)

ID 유형 설명
charPr 0 글자 10pt 함초롬바탕, 기본
charPr 1 글자 10pt 함초롬돋움
charPr 2~6 글자 Skeleton 기본 스타일
paraPr 0 문단 JUSTIFY, 160% 줄간격
paraPr 1~19 문단 Skeleton 기본 (개요, 각주 등)
borderFill 1 테두리 없음 (페이지 보더)
borderFill 2 테두리 없음 + 투명배경 (참조용)

gonmun (공문) — base + 추가

ID 유형 설명
charPr 7 글자 22pt 볼드 함초롬바탕 (기관명/제목)
charPr 8 글자 16pt 볼드 함초롬바탕 (서명자)
charPr 9 글자 8pt 함초롬바탕 (하단 연락처)
charPr 10 글자 10pt 볼드 함초롬바탕 (표 헤더)
paraPr 20 문단 CENTER, 160% 줄간격
paraPr 21 문단 CENTER, 130% (표 셀)
paraPr 22 문단 JUSTIFY, 130% (표 셀)
borderFill 3 테두리 SOLID 0.12mm 4면
borderFill 4 테두리 SOLID 0.12mm + #D6DCE4 배경

report (보고서) — base + 추가

ID 유형 설명
charPr 7 글자 20pt 볼드 (문서 제목)
charPr 8 글자 14pt 볼드 (소제목)
charPr 9 글자 10pt 볼드 (표 헤더)
charPr 10 글자 10pt 볼드+밑줄 (강조 텍스트)
charPr 11 글자 9pt 함초롬바탕 (소형/각주)
charPr 12 글자 16pt 볼드 함초롬바탕 (1줄 제목)
charPr 13 글자 12pt 볼드 함초롬돋움 (섹션 헤더)
paraPr 20~22 문단 CENTER/JUSTIFY 변형
paraPr 23 문단 RIGHT 정렬, 160% 줄간격
paraPr 24 문단 JUSTIFY, left 600 (□ 체크항목 들여쓰기)
paraPr 25 문단 JUSTIFY, left 1200 (하위항목 ①②③ 들여쓰기)
paraPr 26 문단 JUSTIFY, left 1800 (깊은 하위항목 – 들여쓰기)
paraPr 27 문단 LEFT, 상하단 테두리선 (섹션 헤더용), prev 400
borderFill 3 테두리 SOLID 0.12mm 4면
borderFill 4 테두리 SOLID 0.12mm + #DAEEF3 배경
borderFill 5 테두리 상단 0.4mm 굵은선 + 하단 0.12mm 얇은선 (섹션 헤더)

들여쓰기 규칙: 공백 문자가 아닌 반드시 paraPr의 left margin 사용. □ 항목은 paraPr 24, 하위 ①②③ 는 paraPr 25, 깊은 – 항목은 paraPr 26.

섹션 헤더 규칙: paraPr 27 + charPr 13 조합. 문단 테두리(borderFillIDRef=”5″)로 상단 굵은선 + 하단 얇은선 자동 표시.

minutes (회의록) — base + 추가

ID 유형 설명
charPr 7 글자 18pt 볼드 (제목)
charPr 8 글자 12pt 볼드 (섹션 라벨)
charPr 9 글자 10pt 볼드 (표 헤더)
paraPr 20~22 문단 CENTER/JUSTIFY 변형
borderFill 3 테두리 SOLID 0.12mm 4면
borderFill 4 테두리 SOLID 0.12mm + #E2EFDA 배경

proposal (제안서/사업개요) — base + 추가

시각적 구분이 필요한 공식 문서용. 색상 배경 헤더바와 번호 배지를 표(table) 기반 레이아웃으로 구현.

ID 유형 설명
charPr 7 글자 20pt 볼드 함초롬바탕 (문서 제목)
charPr 8 글자 14pt 볼드 함초롬바탕 (소제목)
charPr 9 글자 10pt 볼드 함초롬바탕 (표 헤더)
charPr 10 글자 14pt 볼드 흰색 함초롬돋움 (대항목 번호, 녹색 배경)
charPr 11 글자 11pt 볼드 흰색 함초롬돋움 (소항목 번호, 파란 배경)
paraPr 20 문단 CENTER, 160% 줄간격
paraPr 21 문단 CENTER, 130% (표 셀)
paraPr 22 문단 JUSTIFY, 130% (표 셀)
borderFill 3 테두리 SOLID 0.12mm 4면
borderFill 4 테두리 SOLID 0.12mm + #DAEEF3 배경
borderFill 5 테두리 올리브녹색 배경 #7B8B3D (대항목 번호 셀)
borderFill 6 테두리 연한 회색 배경 #F2F2F2 + 회색 테두리 (대항목 제목 셀)
borderFill 7 테두리 파란색 배경 #4472C4 (소항목 번호 배지)
borderFill 8 테두리 하단 테두리만 #D0D0D0 (소항목 제목 영역)

proposal 레이아웃 패턴

대항목 헤더 (2셀 표: 번호 + 제목):

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

소항목 헤더 (2셀 표: 번호배지 + 제목):

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

워크플로우 2: 기존 문서 편집 (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

워크플로우 3: 읽기/텍스트 추출

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)

워크플로우 4: 검증

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

검증 항목: ZIP 유효성, 필수 파일 존재, mimetype 내용/위치/압축방식, XML well-formedness


워크플로우 5: 레퍼런스 기반 문서 생성

사용자가 제공한 HWPX 파일을 분석하여 동일한 레이아웃의 문서를 생성하는 워크플로우.

흐름

  1. 분석 — analyze_template.py로 레퍼런스 문서 심층 분석
  2. header.xml 추출 — 레퍼런스의 스타일 정의를 그대로 사용
  3. section0.xml 작성 — 분석 결과의 구조를 따라 새 내용으로 작성
  4. 빌드 — 추출한 header.xml + 새 section0.xml로 빌드
  5. 검증

사용법

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

분석 출력 항목

항목 설명
폰트 정의 hangul/latin 폰트 매핑
borderFill 테두리 타입/두께 + 배경색 (각 면별 상세)
charPr 글꼴 크기(pt), 폰트명, 색상, 볼드/이탤릭/밑줄/취소선, fontRef
paraPr 정렬, 줄간격, 여백(left/right/prev/next/intent), heading, borderFillIDRef
문서 구조 페이지 크기, 여백, 페이지 테두리, 본문폭
본문 상세 모든 문단의 id/paraPr/charPr + 텍스트 내용
표 상세 행×열, 열너비 배열, 셀별 span/margin/borderFill/vertAlign + 내용

핵심 원칙

  • charPrIDRef/paraPrIDRef를 그대로 사용: 추출한 header.xml의 스타일 ID를 변경하지 말 것
  • 열 너비 합계 = 본문폭: 분석 결과의 열너비 배열을 그대로 복제
  • rowSpan/colSpan 패턴 유지: 분석된 셀 병합 구조를 정확히 재현
  • cellMargin ë³´ì¡´: 분석된 셀 여백 값을 동일하게 적용

스크립트 요약

스크립트 용도
scripts/build_hwpx.py 핵심 — 템플릿 + XML → HWPX 조립
scripts/analyze_template.py HWPX 심층 분석 (레퍼런스 기반 생성의 청사진)
scripts/office/unpack.py HWPX → 디렉토리 (XML pretty-print)
scripts/office/pack.py 디렉토리 → HWPX (mimetype first)
scripts/validate.py HWPX 파일 구조 검증
scripts/text_extract.py HWPX 텍스트 추출

단위 변환

값 HWPUNIT 의미
1pt 100 기본 단위
10pt 1000 기본 글자크기
1mm 283.5 밀리미터
1cm 2835 센티미터
A4 폭 59528 210mm
A4 높이 84186 297mm
좌우여백 8504 30mm
본문폭 42520 150mm (A4-좌우여백)

Critical Rules

  1. HWPX만 지원: .hwp(바이너리) 파일은 지원하지 않는다. 사용자가 .hwp 파일을 제공하면 한글 오피스에서 .hwpx로 다시 저장하도록 안내할 것. (파일 → 다른 이름으로 저장 → 파일 형식: HWPX)
  2. secPr 필수: section0.xml 첫 문단의 첫 run에 반드시 secPr + colPr 포함
  3. mimetype 순서: HWPX 패키징 시 mimetype은 첫 번째 ZIP 엔트리, ZIP_STORED
  4. 네임스페이스 보존: XML 편집 시 hp:, hs:, hh:, hc: 접두사 유지
  5. itemCnt 정합성: header.xml의 charProperties/paraProperties/borderFills itemCnt가 실제 자식 수와 일치
  6. ID 참조 정합성: section0.xml의 charPrIDRef/paraPrIDRef가 header.xml 정의와 일치
  7. venv 사용: 프로젝트의 .venv/bin/python3 (lxml 패키지 필요)
  8. 검증: 생성 후 반드시 validate.py로 무결성 확인
  9. 레퍼런스: 상세 XML 구조는 $SKILL_DIR/references/hwpx-format.md 참조
  10. build_hwpx.py 우선: 새 문서 생성은 build_hwpx.py 사용 (python-hwpx API 직접 호출 지양)
  11. 빈 줄: <hp:t/> 사용 (self-closing tag)