HWP (한글)
OfficeCLI를 통한 HWP/HWPX 한국어 문서 생성, 읽기, 편집
기본 활성화: 예 바이너리 HWP: 실험적
.hwp 및 .hwpx 파일만 처리합니다. 작업에 DOCX, PPTX, XLSX 또는 PDF가 관련된 경우 활성화되지 않습니다 — 대신 해당 포맷 전용 스킬을 사용하세요.빠른 참조
작업별 명령어 조회 표입니다. 각 행은 해당 작업의 지원 여부와 사용할 명령어를 보여줍니다.
| 작업 | 상태 | 명령어 |
|---|---|---|
| 기존 .hwpx와 동일한 서식 | Yes | cp source.hwpx target.hwpx && officecli open target.hwpx |
| 템플릿 기반 생성 | Yes | python3 scripts/build_hwpx.py --template {base|gonmun|minutes|proposal|report} |
| 새 .hwpx 생성 | Yes | officecli create file.hwpx |
| 마크다운에서 생성 | Yes | officecli create file.hwpx --from-markdown input.md |
| .hwpx 읽기 / 분석 | Yes | view text|annotated|outline|stats|html|markdown|tables|forms|objects |
| 기존 .hwpx 편집 | Yes | set, add, remove, move, swap |
| 레이블 기반 채우기 | Yes | set /table/fill --prop 'fill:label=val' |
| 양식 인식 | Yes | view forms --auto |
| 표 맵 | Yes | view tables |
| 마크다운 내보내기 | Yes | view markdown |
| 수식 (수식) | Yes | add --type equation --prop 'script={1 over 2}' |
| 오브젝트 찾기 | Yes | view objects |
| 쿼리 (확장) | Yes | query 'tc[text~=홍길동]', :has(), > 결합자 |
| 템플릿 병합 | Yes | merge template.hwpx out.hwpx --data '{"key":"val"}' |
| 요소 교환 | Yes | swap file.hwpx '/p[1]' '/p[2]' |
| 단 나누기 | Yes | add --type columnbreak --prop cols=2 |
| 이미지 / 떠다니는 개체 | Yes | add --type picture --prop anchor=page --prop halign=center |
| 문서 비교 | Yes | compare a.hwpx b.hwpx (LCS 차이점 비교 + 표 비교) |
| 보안 검증 | Yes | ZIP 폭탄, 경로 탐색, 심링크, XXE 방어 |
| 손상된 ZIP 복구 | Yes | Local File Header 스캔을 통한 손상된 HWPX 자동 복구 |
| HTML 미리보기 | Yes | view html --browser |
| 실시간 미리보기 감시 | Yes | watch file.hwpx |
| .hwpx 검증 | Yes | validate (9단계 검사) |
| 원본 XML | Yes | raw, raw-set |
| 워터마크 (이미지) | Yes | add --type watermark --prop src=img.png |
| 패턴 매칭 편집 | Python L4 | scripts/hwpx_cli.py open → 패턴으로 XML 편집 → save |
| 시각적 QA | Python L3 | scripts/contact_sheet.py + 서브에이전트 검토 |
| 새 양식 필드 생성 | Blocked | 소스 프로토타입 존재; 한컴 검증 미완료 |
| 새 .hwp (바이너리) 생성 | Experimental | officecli create file.hwp --json |
| .hwp (바이너리) 읽기/내보내기 | Experimental | officecli view file.hwp text --json + svg/png/pdf/markdown |
| .hwp 텍스트/필드 편집 | Experimental | officecli hwp --json 레시피 |
| HWPX를 .hwp로 내보내기 | Experimental | officecli set input.hwpx /save-as-hwp --prop output=out.hwp --json |
| .hwp를 .hwpx로 변환 | Fallback | scripts/hwp_convert.py IN.hwp OUT.hwpx |
"~해줘" 사용 예시
이 스킬을 트리거하는 자연스러운 한국어 프롬프트입니다. 필요한 것을 설명하기만 하면 됩니다.
--template gonmun으로 템플릿 조합을 트리거한 뒤, /table/fill을 사용하여 문서번호, 수신, 참조, 제목 등의 레이블-값 필드를 채웁니다.view tables, view forms --auto, view stats를 실행하여 문서의 구조적 분석 결과를 제공합니다.officecli set form.hwpx / --prop 'fill:성명=홍길동' --prop 'fill:연락처=010-1234-5678'--template minutes로 생성한 뒤, 날짜, 장소, 참석자, 안건 항목에 대한 구조화된 필드를 채웁니다.officecli hwp doctor --json으로 네이티브 rhwp 지원 여부를 확인합니다. 준비되면 officecli view file.hwp text --json을 사용합니다. 그렇지 않으면 scripts/hwp_reader.py로 대체합니다.편집 에스컬레이션 단계
주요 도구가 작업을 처리할 수 없을 때, 스킬은 4단계를 거쳐 에스컬레이션합니다. 낮은 단계가 우선이며, 높은 단계는 필요한 경우에만 사용됩니다.
| 단계 | 조건 | 도구 |
|---|---|---|
| L1 OfficeCLI 고수준 | 일반적인 add/set/remove, 레이블 채우기, 보기 모드 | officecli add/set/remove/query/view/merge |
| L2 OfficeCLI raw/raw-set | section0.xml / header.xml 직접 수정 | officecli raw FILE /Contents/section0.xml |
| L3 Python 스크립트 | 대량 찾기/바꾸기, 템플릿 조합, 패턴 매칭 | python3 scripts/hwpx_cli.py ... 또는 scripts/build_hwpx.py |
| L4 압축 해제 → XML 편집 → 재압축 | 수능 시험지, 규정, 다중 파일 XML 편집 | hwpx_cli.py open → work/Contents/*.xml 편집 → lineseg 제거 → save |
에스컬레이션 시그널
- OfficeCLI가 사용자 정의 스타일을 추가할 수 없는 경우 → L2 (raw-set header.xml) +
reference/header-xml-guide.md참조 - 사용자 정의 템플릿 오버레이 → L3 (
scripts/build_hwpx.py) +reference/style_id_maps.md참조 - HWP 바이너리 입력 → 먼저
officecli hwp doctor --json확인; rhwp 네이티브 준비 시 사용, 아니면 L3 - 다중 파일 패턴 매칭 (시험지, 규정) → L4
- 스타일 ID 조회 → 먼저
reference/style_id_maps.md참조
핵심 워크플로우
생성 및 가져오기
# 빈 문서
officecli create doc.hwpx
# 마크다운에서 생성 (기본 JUSTIFY 정렬)
officecli create doc.hwpx --from-markdown input.md
# 왼쪽 정렬 마크다운 가져오기
officecli create doc.hwpx --from-markdown input.md --align left
# rhwp 브릿지를 통한 바이너리 HWP
officecli create file.hwp --json
# 데이터로 템플릿 병합
officecli merge template.hwpx out.hwpx --data '{"이름":"홍길동"}'
officecli merge template.hwpx out.hwpx --data data.json
# 템플릿 조합 (구조화된 문서에 권장)
python3 scripts/build_hwpx.py --template gonmun --output gonmun.hwpx
보기 모드
officecli view doc.hwpx text # 줄 번호가 있는 텍스트
officecli view doc.hwpx annotated # 경로 + 스타일 상세
officecli view doc.hwpx outline # 제목만
officecli view doc.hwpx stats # 문서 통계
officecli view doc.hwpx html --browser # A4 HTML 미리보기
officecli view doc.hwpx markdown # GFM 마크다운 내보내기
officecli view doc.hwpx tables # 표 2D 그리드 + 레이블 맵
officecli view doc.hwpx forms --auto # CLICK_HERE + 레이블-값 자동 감지
officecli view doc.hwpx forms --auto --json # AI 파이프라인용 JSON
officecli view doc.hwpx objects # 그림/필드/책갈피/수식 목록
officecli view doc.hwpx objects --object-type field # 유형별 필터
officecli view doc.hwpx styles # charPr/paraPr 스타일
officecli view doc.hwpx issues # 9단계 검증 문제
officecli view file.hwpx를 실행하면 오류가 발생합니다. 반드시 모드를 지정해야 합니다: text, tables, markdown 등.편집 작업
# 텍스트와 글꼴 크기로 문단 추가
officecli add doc.hwpx /section[1] --type paragraph --prop text="content" --prop fontsize=11
# 표 추가
officecli add doc.hwpx /section[1] --type table --prop rows=3 --prop cols=4
# 속성 설정 (굵게, 정렬)
officecli set doc.hwpx '/section[1]/p[1]' --prop bold=true --prop align=CENTER
# 텍스트 찾기 및 바꾸기
officecli set doc.hwpx / --prop find="old" --prop replace="new"
# 요소 제거
officecli remove doc.hwpx /section[1]/p[3]
# 두 요소 교환
officecli swap doc.hwpx '/p[1]' '/p[2]'
레이블 채우기 (표 자동 채우기)
# 레이블로 채우기 (fill: 접두사)
officecli set doc.hwpx / --prop 'fill:대표자=홍길동' --prop 'fill:연락처=010-1234'
# 방향 채우기: right (기본), down, left, up
officecli set doc.hwpx / --prop 'fill:주소>down=서울시'
# 약식 (fill: 접두사 생략 가능, /table/fill 경로 사용 시)
officecli set doc.hwpx /table/fill --prop '이름=김서준'
쿼리 (확장 구문)
officecli query doc.hwpx 'p' # 모든 문단
officecli query doc.hwpx 'tc[text~=홍길동]' # 셀 텍스트 검색
officecli query doc.hwpx 'run[bold=true]' # 굵은 텍스트 런
officecli query doc.hwpx 'p:has(tbl)' # 표를 포함하는 문단
officecli query doc.hwpx 'tbl > tr > tc[colSpan!=1]' # 병합된 셀
officecli query doc.hwpx 'run[fontsize>=20]' # 20pt 이상 글꼴
officecli query doc.hwpx 'p[heading=1]' # 제목 1
연산자: =, !=, ~= (포함), >=, <=
의사 선택자: :empty, :contains(text), :has(child), :first, :last
가상 속성: text, bold, italic, fontsize, colSpan, rowSpan, heading
상주 모드 (실시간 연결)
officecli open doc.hwpx # 즉시 반환; 데몬이 백그라운드에서 실행
officecli view text # 다시 열지 않고 보기
officecli set '/p[1]' --prop bold=true
officecli close # 세션 닫기
officecli open을 백그라운드 셸 작업으로 실행하지 마세요. 즉시 반환되며 데몬이 자동으로 백그라운드에서 실행됩니다. 모니터링되는 백그라운드 셸로 실행하면 좀비 프로세스와 파일 잠금이 발생합니다.배치 모드
officecli batch doc.hwpx <<'EOF'
view text
view stats
view forms --auto
EOF
비교
officecli compare a.hwpx b.hwpx # 텍스트 차이점 (기본)
officecli compare a.hwpx b.hwpx --mode outline # 제목 차이점
officecli compare a.hwpx b.hwpx --mode table --json # 표 차이점 JSON
LCS DP 정렬을 사용합니다 (1000만 셀 초과 시 탐욕 알고리즘으로 대체). 표 유사도: 차원 가중치 0.3 + 내용 가중치 0.7. 페이지 범위 필터링: --pages "1-3,5".
이미지 및 워터마크
# 인라인 이미지
officecli add doc.hwpx /section[1] --type picture --prop path=/path/to/image.png
# 페이지 중앙 떠다니는 이미지
officecli add doc.hwpx /section[1] --type picture \
--prop path=/path/to/image.png \
--prop anchor=page --prop halign=center --prop valign=middle
# 워터마크 (불투명 RGB PNG 권장)
officecli add doc.hwpx /section[1] --type watermark \
--prop src=/path/to/watermark.png --prop bright=0 --prop contrast=0
감시 및 HTML 미리보기
officecli watch doc.hwpx # 파일 변경 시 HTML 자동 새로고침
officecli unwatch doc.hwpx # 중지
officecli view doc.hwpx html --browser # 단발성 A4 미리보기
템플릿 조합 시스템
HWP는 고유한 기본 + 오버레이 템플릿 시스템을 사용합니다. 공문/보고서/회의록/제안서의 대부분의 HWPX 생성은 officecli create 빈 문서 대신 이 시스템을 사용해야 합니다.
사용 가능한 템플릿
| 템플릿 | 용도 | 주요 필드 |
|---|---|---|
base | 빈 HWPX 골격 | mimetype, META-INF, 빈 header/section |
gonmun | 공문서 (공문) | 문서번호, 수신, 참조, 제목, 본문 |
minutes | 회의록 (회의록) | 일시, 장소, 참석자, 안건, 결정사항 |
proposal | 제안서 (제안서) | 제안개요, 배경, 내용, 기대효과 |
report | 보고서 (보고서) | 요약, 현황, 분석, 제언 |
방법 1: build_hwpx.py (권장)
python3 scripts/build_hwpx.py --template report --output Q4Report.hwpx
# 그런 다음 officecli로 내용 편집
officecli open Q4Report.hwpx
officecli set Q4Report.hwpx /table/fill --prop '제목=2026 Q4 보고'
# ... 계속 편집 ...
officecli close Q4Report.hwpx
방법 2: 수동 오버레이 (커스터마이징용)
# 1. 기본 골격 복사
cp -r templates/base/ work/
# 2. 도메인별 스타일 오버레이
cp -r templates/gonmun/* work/Contents/
# 3. 필요에 따라 header.xml과 section0.xml 편집
# 참조: reference/header-xml-guide.md, reference/section0-xml-guide.md
# 스타일 ID: reference/style_id_maps.md
# 4. HWPX로 재압축 (ZIP + 정리 + 최소화)
python3 scripts/ooxml/pack.py work/ out.hwpx
# 5. 검증
officecli validate out.hwpx
참조 기반 편집
사용자가 "X.hwpx처럼 서식 맞춰줘", "공문 양식처럼", "기존 보고서 스타일", 또는 소스 파일을 제공하는 경우 — 소스에서 시작하되 처음부터 다시 만들지 마세요.
워크플로우
- 소스 복사:
cp source.hwpx target.hwpx— header.xml (스타일), section0.xml (구조), META-INF를 상속합니다 - 열기:
officecli open target.hwpx— 데몬이 즉시 반환합니다 (백그라운드로 실행하지 마세요) - 본문 문단만 제거 —
header.xml(charPr/paraPr/borderFill), META-INF, settings를 유지합니다 - 새 내용 추가 — 기존
styleidref값을 사용하면 자동으로 적용됩니다
header.xml은 모든 스타일 정의 (charPr, paraPr, borderFill, listItems)를 보유합니다. 처음부터 다시 만들면 styleidref 교차 참조가 깨지고, 일관된 시각적 관례가 유실되며, 검증에 실패하고, 10배 더 오래 걸립니다.템플릿 우선순위
- 사용자 제공 소스 파일 — 최우선 템플릿
tests/fixtures/agentic/*.hwpx— 실제와 유사한 샘플 (공문, 보고서, 표가 있는 회의록)templates/{base,gonmun,minutes,proposal,report}/— 템플릿 조합 시스템officecli create빈 문서 — 다른 것이 해당되지 않을 때만 사용
양식 인식 및 채우기
4단계 인식 전략
| # | 전략 | 설명 |
|---|---|---|
| 1 | 인접 셀 레이블-값 | 표 레이블 → 값 감지 (기본) |
| 2 | 헤더 + 데이터 행 | 열 헤더 인식 |
| 3 | 셀 내 패턴 | ☐ 체크박스, keyword( ) 괄호 빈칸, (label: ) 주석 |
| 4 | KV 표 감지 | 16개 한국어 키워드로 자동 감지 트리거 |
3단계 채우기 파이프라인
- 셀 내 패턴: 체크박스
☐→☑, 괄호 빈칸 채우기, 주석 채우기 - 표 레이블-값: 정확 일치 + 접두사 60% 매칭, 4방향 (
right/down/left/up) - 인라인 문단: 표 외부의
"label: value"에 대한 정규식 후방 탐색
AI 양식 채우기 워크플로우
# 1단계: 모든 필드 인식
officecli view form.hwpx forms --auto --json > fields.json
# 2단계: AI가 레이블 -> 값 매핑 (사용자 로직)
# 3단계: 매칭된 필드 채우기
officecli set form.hwpx /table/fill --prop '성 명=홍길동'
바이너리 HWP 지원 (실험적)
네이티브 바이너리 .hwp 작업은 rhwp 브릿지로 구동됩니다. 모든 작업은 기능 게이트가 적용되어 있으므로 — 지원을 가정하기 전에 항상 준비 상태를 확인하세요.
검색 명령어
# 항상 먼저 실행
officecli hwp doctor --json # 런타임 준비 상태 확인
officecli capabilities --json # 전체 기능 매트릭스
officecli hwp --json # 현재 레시피 및 정책
지원되는 작업 (준비 시)
# 생성
officecli create file.hwp --json
# 보기 / 내보내기
officecli view file.hwp text --json
officecli view file.hwp svg --page 1 --json
officecli view file.hwp png --page 1 --out /tmp/hwp-png --json
officecli view file.hwp pdf --page 1 --out out.pdf --json
officecli view file.hwp markdown --json
officecli view file.hwp thumbnail --out thumb.png --json
officecli view file.hwp info --json
officecli view file.hwp tables --section 0 --json
# 필드 편집
officecli set file.hwp /field --prop name=회사명 --prop value=리지 --prop output=out.hwp --json
# 텍스트 편집
officecli set file.hwp /text --prop find=마케팅 --prop value=브릿지 --prop output=out.hwp --json
# 텍스트 삽입
officecli add file.hwp /text --type paragraph --prop value=새본문 --prop output=out.hwp --json
# 표 셀 편집
officecli set file.hwp /table/cell --prop section=0 --prop parent-para=3 \
--prop control=0 --prop cell=0 --prop value=오피스셀 --prop output=out.hwp --json
# 네이티브 작업 (이스케이프 해치)
officecli view file.hwp native --op get-style-list --json
officecli set file.hwp /native-op --prop op=split-paragraph --prop output=out.hwp --json
# HWPX에서 HWP로 내보내기
officecli set input.hwpx /save-as-hwp --prop output=out.hwp --json
.hwp 수정 시 출력 모드를 우선 사용하세요: --prop output=out.hwp. 제자리 수정 모드는 /text 교체에만, 명시적 요청이 있을 때만, safeInPlace.ready=true 확인 후에만 사용하세요. 제자리 수정 모드에는 반드시 --in-place --backup --verify를 포함해야 합니다.수식 처리 (수식)
HWPX 수식은 한컴의 독자적 스크립트 언어를 사용합니다. MathML도, LaTeX도, OMML도 아닙니다.
| 스크립트 | 결과 |
|---|---|
{1 over 2} | 1/2 (분수) |
sqrt{x} | x의 제곱근 |
x^2, x_i | 위 첨자, 아래 첨자 |
int _0 ^1 f(x)dx | 정적분 |
sum _{i=1} ^n | 시그마 합 |
lim _{x->0} | 극한 |
matrix{a&b # c&d} | 2x2 행렬 |
# 수식 생성
officecli add doc.hwpx /section --type equation --prop 'script=x^2 + y^2 = r^2'
# 모든 수식 보기
officecli view doc.hwpx objects --object-type equation
<hp:script> 텍스트만 편집하세요. 수학 시험 문서 (수능)는 모든 수식에 <hp:equation>이 필요합니다. 수학 표현에 일반 텍스트를 사용하지 마세요.한국어 문서 디자인 원칙
정부 양식 미감 (한국 공공양식 미감)
- 표가 뼈대입니다: 한국 양식은 표 중심입니다. 모든 레이블-값 쌍이 정밀하게 병합된 셀 그리드에 위치합니다. 그리드 구조를 정확히 유지하세요.
- 제목 계층: 제1조 (조) > 제1항 (항) > 제1호 (호). 개요 수준에는
styleidref를 사용하세요. - 고정 여백: 정부 양식은 표준 A4 여백을 사용합니다 (상/하 ~15mm, 좌/우 ~20mm). 기존 문서의 여백을 변경하지 마세요.
- 정렬: 본문 텍스트는 기본적으로 JUSTIFY (양쪽 정렬)입니다. 제목은 CENTER일 수 있습니다. 공식 문서에서 본문 텍스트에 LEFT를 사용하지 마세요.
균등분할 감지 (균등분할)
한국 양식에서는 셀 내 이름에 균등 문자 간격을 자주 사용합니다: "홍 길 동" (각 글자 사이에 공백). 이것은 표시 관례이지 데이터가 아닙니다.
- 읽기: 균등 공백을 제거하여 실제 값을 얻습니다 (
"홍길동") - 쓰기: 템플릿 셀이 균등 간격을 사용하는 경우, 이에 맞게 공백을 삽입합니다 (2자:
"이 준", 3자:"홍 길 동", 4자:"남궁민수") - 감지 정규식:
^(\S)\s(\S)\s(\S)$등 (1개 공백으로 구분된 단일 문자 그룹)
문서 유형 분류
| 유형 | 주요 신호 | 예시 |
|---|---|---|
exam | 수식 10개 이상, rect 객체 | 수능/모의고사 시험지 |
form | 표 3개 이상, 체크박스 (☐/■) | 대학 신청서, 정부 양식 |
regulation | ○ 글머리 10개 이상, 별첨/조항 참조, 표 10개 이상 | 운영지침, 내규, 시행세칙 |
report | 긴 텍스트, 표 적음 | 보고서, 논문 |
mixed | 위의 어느 것도 해당 없음 | 사업계획서 |
필수 검증
# 1. 구조 검증 (반드시 통과해야 함)
officecli validate output.hwpx
# 2. PDF 시각 검증 (반드시 확인해야 함)
soffice --headless --convert-to pdf --outdir /tmp output.hwpx
# 확인: 표 위치, 안내 텍스트 제거 여부, 체크박스 정확성,
# 병합 셀 텍스트가 올바른 행에 있는지, 숫자 손상 여부
# 3. 서브에이전트를 통한 시각적 QA (reference/visual_qa_prompt.md 사용)
python3 scripts/contact_sheet.py /tmp/output.pdf sheet.png
# 4. 한컴오피스가 있으면, .hwpx를 직접 열어서도 확인
납품 전 체크리스트
officecli validate통과 (오류 0개)soffice --headless --convert-to pdf→ 시각 확인- 표 셀이 올바른 위치에 있는지 (cellAddr 매핑)
- 안내 텍스트 (※, 예시) 완전 제거
- 체크박스 ☐/■가 의도된 셀에만 있는지
- 병합 셀 텍스트가 올바른 행에 있는지
- 한컴오피스가 있으면 .hwpx를 직접 열어서 확인
보안
| 검사 | 제한 |
|---|---|
| ZIP 폭탄 | 1000개 항목, 200 MB, 100:1 비율 |
| 경로 탐색 | null 바이트, .., 절대 경로, 드라이브 문자, 심링크 |
| XXE | DtdProcessing.Prohibit |
| 표 크기 | 200열 x 10,000행 |
참조 자료 및 스크립트
참조 문서 (reference/)
| 파일 | 참조 시점 | 내용 |
|---|---|---|
reference/hwpx-format.md | 직접 XML 편집 전 | OWPML ZIP 구조, 네임스페이스, 파일 레이아웃, mimetype |
reference/header-xml-guide.md | charPr/paraPr/borderFill 스타일 추가/수정 시 | header.xml에 새 스타일을 추가하는 방법 |
reference/section0-xml-guide.md | 문단/표/혼합 서식 XML 작업 시 | section0.xml 본문용 XML 템플릿 |
reference/style_id_maps.md | 템플릿 오버레이를 위한 스타일 ID 조회 시 | 모든 템플릿의 전체 스타일 ID 인덱스 |
reference/dependencies.md | 최초 설정 / 환경 확인 시 | 필요한 Python/시스템 패키지 |
reference/visual_qa_prompt.md | 서브에이전트를 통한 시각적 QA 시 | PDF 이미지 검사용 즉시 사용 가능한 프롬프트 |
reference/table_templates/*.xml | 미리 만들어진 표 삽입 시 | 2x6, 3x3, 4x4, 5x4 그리드 XML 조각 |
Python 스크립트 (scripts/)
| 스크립트 | 용도 | 명령어 |
|---|---|---|
hwpx_cli.py | 통합 Python CLI (14개 이상 명령) | python3 scripts/hwpx_cli.py {command} ... |
build_hwpx.py | 템플릿 기반 생성 | python3 scripts/build_hwpx.py --template {type} |
analyze_template.py | 템플릿 구조 검사 | python3 scripts/analyze_template.py work/ |
create_document.py | 빈 또는 사용자 정의 HWPX 생성 | python3 scripts/create_document.py OUT.hwpx |
table_builder.py | Python 객체에서 표 XML 생성 | 내부적으로 사용 |
page_guard.py | 문단/표/텍스트 드리프트 감지 | python3 scripts/page_guard.py -r ref.hwpx -o out.hwpx |
contact_sheet.py | QA 컨택트 시트 (페이지 그리드 이미지) | python3 scripts/contact_sheet.py INPUT.pdf sheet.png |
validate.py | 9단계 구조 검증 | python3 scripts/validate.py INPUT.hwpx |
hwp_reader.py | HWP 5.0 바이너리 읽기 (읽기 전용) | python3 scripts/hwp_reader.py INPUT.hwp |
hwp_convert.py | HWP → HWPX 변환 | python3 scripts/hwp_convert.py IN.hwp OUT.hwpx |
text_extract.py | HWPX에서 일반 텍스트 추출 | python3 scripts/text_extract.py INPUT.hwpx |
패턴 매칭 편집 (L4 대체)
officecli set/find-replace로 처리할 수 없는 복잡한 양식 편집 — 수능 시험지, 다중 섹션 규정, 단편화된 텍스트 노드 등에 사용합니다.
핵심 흐름
# HWPX 압축 해제
python3 scripts/hwpx_cli.py open input.hwpx
# work/Contents/의 XML 파일 편집
# (lineseg는 hwpx_cli.py에 의해 자동 제거됨)
# 재압축
python3 scripts/hwpx_cli.py save output.hwpx
주요 패턴
| 패턴 | 설명 |
|---|---|
| Lineseg 제거 | 직접 XML 쓰기 시마다 오래된 <hp:linesegarray> 캐시 제거 |
| 체크박스 치환 | ☐ → ☑, 다중 <t> 노드 처리 포함 |
| 균등분할 정규화 | "홍 길 동" ↔ "홍길동" 변환 |
| p[0] 몬스터 | secPr + tbl + 문제 1 텍스트가 첫 번째 문단에 병합 |
| 수식 인터리빙 | <t> ↔ <equation> 교대 — 텍스트 추출 시 수식 건너뛰기 |
Lineseg 제거 (중요)
HWPX XML을 직접 편집할 때 (officecli나 scripts/hwpx_cli.py를 통하지 않고), 반드시 모든 <hp:linesegarray> 요소를 제거해야 합니다. 오래된 레이아웃 캐시로 인해 문자가 한 줄에 겹쳐 표시됩니다.
import re
xml = re.sub(r'<(?:hp:)?linesegarray[^>]*>.*?</(?:hp:)?linesegarray>', '', xml, flags=re.DOTALL)
xml = re.sub(r'<(?:hp:)?linesegarray[^/]*/>', '', xml) # self-closing
officecli와 scripts/hwpx_cli.py는 lineseg 제거를 자동으로 처리합니다. 이 규칙은 Python으로 직접 XML을 편집하는 경우에만 적용됩니다.흔한 실수
| 실수 | 올바른 방법 |
|---|---|
--props text=Hello | --prop text=Hello — 항상 단수형 --prop |
/body/p[1] 경로 | HWPX는 /section[1]/p[1]을 사용합니다 — body가 아닌 section 기반 |
셸에서 [N]을 따옴표 없이 사용 | "/section[1]/p[1]" — 경로는 항상 따옴표로 감싸세요 |
fontsize 누락 | --prop fontsize=11 항상 지정 — charPr 0 오염 방지 |
officecli view file.hwpx (모드 없음) | 오류 발생. 반드시 지정: text, markdown, tables 등 |
| 수동 표 매핑 | view tables가 수동 검사를 대체합니다 |
| 템플릿에서 header.xml 스타일 재생성 | 먼저 cp source.hwpx target.hwpx. reference/style_id_maps.md 참조 |
officecli open을 백그라운드 셸로 실행 | 포그라운드에서 실행 — 즉시 반환되며 데몬이 자동으로 백그라운드에서 실행 |
| lineseg 제거 없이 XML 직접 편집 | 오래된 캐시로 텍스트가 겹칩니다. hwpx_cli.py를 사용하거나 수동으로 제거하세요 |
| reference/ 참조 없이 사용자 정의 스타일 작업 | reference/header-xml-guide.md + reference/style_id_maps.md는 필수입니다 |
안티패턴 (반드시 피해야 함)
- 수학 시험에 수식이 없으면 출력이 깨집니다 — 수능 문서에는
<hp:equation>요소가 필요합니다 - 보호 장치 없는 HWP 바이너리 덮어쓰기 금지 —
--prop output=...을 우선 사용;safeInPlace.ready=true일 때만 안전한 제자리 수정 사용 - rhwp에 네이티브 프리미티브가 있을 때 가짜 HWPX 대체 금지 — OfficeCLI에 해당 경로가 없으면 격차를 보고하고 승인을 위해 중단
- lineseg 제거 없이 XML 편집 금지 — 오래된 캐시로 텍스트가 겹칩니다
- 고정 레이아웃 시험에 보이는 QA 마커 금지 — 대신 스크린샷이나 부속 증거를 사용하세요
- 교차 포맷 스킬 로딩 금지 — 이 스킬은
.hwp/.hwpx전용입니다 - 템플릿에 존재하는 스타일 재생성 금지 — 먼저
cp하고reference/style_id_maps.md를 참조하세요 - 참조 자료 무시 금지 —
header-xml-guide.md,section0-xml-guide.md,style_id_maps.md는 사용자 정의 XML 작업에 필수입니다
의존성
| 도구 | 용도 | 필수 여부 |
|---|---|---|
officecli (전역) | 주요 HWPX CLI + 실험적 rhwp 기반 HWP 브릿지 | 필수 |
python3 | 대체 스크립트 (scripts/*.py) | L3/L4에 필수 |
lxml | scripts/*용 XML 처리 | L3/L4에 필수 |
pyhwp | 레거시 HWP 5.0 바이너리 읽기/변환 대체 수단 | HWP→HWPX 대체에 필수 |
soffice (LibreOffice) | PDF 변환 + 시각 검증 | 권장 |
Java (JAVA_HOME) | H2Orestart HWP 변환 엔진 | HWP→HWPX 전용 |
dotnet | officecli 소스 빌드 | 빌드 전용 |
사전 요구 사항 확인
# OfficeCLI (필수)
which officecli >/dev/null 2>&1 || echo "WARN: OfficeCLI not installed"
# LibreOffice (권장, 필요 시 자동 설치)
which soffice >/dev/null 2>&1 || echo "INFO: LibreOffice not installed"
# Python 패키지 (L3/L4에 선택 사항)
python3 -c "import lxml; import pyhwp" 2>/dev/null || echo "OPTIONAL: pip install lxml pyhwp"
# Java (HWP 변환 전용)
echo "JAVA_HOME=$JAVA_HOME"
도구 검색
추측하기 전에 항상 도움말에서 구문을 확인하세요.
officecli --help
officecli hwp --json
officecli hwp doctor --json
officecli capabilities --json
officecli view --help
officecli set --help
python3 scripts/hwpx_cli.py --help
python3 scripts/build_hwpx.py --help
시험 XML 구조 패턴
수능 스타일의 시험지는 고정 레이아웃 제약으로 인해 특별한 처리가 필요합니다.
| 패턴 | 설명 | 감지 |
|---|---|---|
| 페이지/단 나누기 | pageBreak="1" / columnBreak="1" | 페이지 경계 = 문제 그룹 경계 |
| p[0] 몬스터 | secPr + colPr + 제목 tbl + 문제 1 텍스트가 병합 | 첫 번째 문단에 모두 포함 |
| 수식 인터리빙 | <t> ↔ <equation> 교대 | 텍스트 추출 시 수식 건너뛰기 |
| 답안 선택지 | ① + 5개 <equation> (5지선다) | 답안 문단 자동 감지 |
| 텍스트 단편화 | 1-2자 <t> 분리 (HWP 변환) | 모든 텍스트를 연결한 뒤 매칭 |
| 2단 레이아웃 | <hp:colPr type="NEWSPAPER" colCount="2"> | 시험 전용 레이아웃 |
[CU TEMPLATE EDIT ...]이나 VISUAL QA 같은 문자열은 시각적으로 치명적인 실패입니다. 대신 전후 스크린샷을 캡처하세요.HWP → HWPX 변환
포맷 감지
file doc.hwpx # "Zip archive" -> HWPX (ZIP + OWPML XML)
file doc.hwp # "HWP Document" -> HWP 5.0 바이너리
구조적 차이
| 항목 | 네이티브 HWPX | HWP → HWPX 변환본 |
|---|---|---|
| 텍스트 단위 | 런당 짧은 <t> | 전체 문단이 하나의 <t>에 |
| 제목 p[0] | secPr + tbl + 내용 | 페이지 번호 조각 <t>20</t> + <t>1</t>이 혼재 |
| 편집 | 런 수준의 정밀한 교체 | 원시 문자열 교체 또는 전체 문단 교환 필요 |
변환 파일 편집 전략
- 제목: 런 인식 교체 —
set_run_text(p0, 'old', 'new')(페이지 번호 런 건너뛰기) - 본문: 직렬화된 XML에 대한 원시 문자열 교체 —
sec0.replace(old, new) - 다중
<t>셀:ReplaceTextInCell()사용 — 모든<t>를 연결 → 매칭 → 재분배