Skip to content

Latest commit

ย 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

hangulang

hangulang์€ HWP 5.0 ๋ฐ HWPX ๋ฌธ์„œ(ํ•œ์ปด์˜คํ”ผ์Šค / ํ•œ๊ธ€)๋ฅผ ์œ„ํ•œ Rust ๊ธฐ๋ฐ˜ semantic extraction toolkit์ž…๋‹ˆ๋‹ค.

ํ˜„์žฌ primary exporter๋Š” DocLang v0.6์ž…๋‹ˆ๋‹ค. DocLang์€ LF AI & Data Foundation์ด ๋งŒ๋“  AI ๋„ค์ดํ‹ฐ๋ธŒ ยท LLM ํ† ํฌ๋‚˜์ด์ € ์นœํ™”์  XML ๋ฌธ์„œ ํฌ๋งท์ž…๋‹ˆ๋‹ค.

hangulang์€ rhwp ํŒŒ์„œ ์ฝ”์–ด ์œ„์—์„œ ๋ฌธ์„œ์˜ ์˜๋ฏธ ๊ตฌ์กฐ(์ œ๋ชฉ, ๋ชฉ๋ก, ํ‘œ, ์ธ๋ผ์ธ ์„œ์‹, ์ˆ˜์‹, ๊ฐ์ฃผ, ๋จธ๋ฆฌ๋ง/๊ผฌ๋ฆฌ๋ง), ์ด๋ฏธ์ง€ ๋ฆฌ์†Œ์Šค, ์†์‹ค ๋ณด๊ณ , ๊ทธ๋ฆฌ๊ณ  โ€” ์„ ํƒ์ ์œผ๋กœ โ€” ๋ ˆ์ด์•„์›ƒ ์ขŒํ‘œ(bounding box)๋ฅผ ์•ˆ์ •์ ์ธ ๋‚ด๋ถ€ IR๋กœ ๋‚ฎ์ถฅ๋‹ˆ๋‹ค. ํ˜„์žฌ ์ด IR์—์„œ DocLang XML, semantic payload, Markdown, resource asset/URI ์ฐธ์กฐ๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ƒํƒœ: v0.1 โ€” ํ™œ๋ฐœํžˆ ๊ฐœ๋ฐœ ์ค‘. ํ˜„์žฌ DocLang exporter ์ถœ๋ ฅ์€ ๊ณต์‹ DocLang ๋ ˆํผ๋Ÿฐ์Šค ๊ฒ€์ฆ๊ธฐ(doclang validate)๋กœ ๊ฒ€์ฆ๋ฉ๋‹ˆ๋‹ค. JSON/Markdown/resource exporter์™€ rhwp ๊ธฐ๋ฐ˜ bbox join์€ unit/golden ํ…Œ์ŠคํŠธ๋กœ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ๋งคํ•‘ ๋ฒ”์œ„๋Š” ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.


์™œ ๋งŒ๋“ค์—ˆ๋‚˜

HWP/HWPX๋Š” ํ•œ๊ตญ ๊ณต๊ณต๊ธฐ๊ด€, ๋ฒ•๋ฌด, ๊ต์œก, ๊ธฐ์—… ๋ฌธ์„œ ์›Œํฌํ”Œ๋กœ์—์„œ ์—ฌ์ „ํžˆ ์ค‘์š”ํ•˜์ง€๋งŒ, ๊ตฌ์กฐํ™”๋œ extraction ๋„๊ตฌ ์ƒํƒœ๊ณ„๋Š” PDF/DOCX์— ๋น„ํ•ด ์–‡์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด HWP ์ถ”์ถœ๊ธฐ๋Š” ๋Œ€๊ฐœ plain text ๋˜๋Š” Markdown์„ ํƒ€๊นƒ์œผ๋กœ ํ•˜๋ฉฐ, ๋ณ‘ํ•ฉ ์…€, ์ œ๋ชฉ ์œ„๊ณ„, ์ˆ˜์‹, ๊ฐ์ฃผ, ์ด๋ฏธ์ง€, ๋ ˆ์ด์•„์›ƒ provenance๋ฅผ ์žƒ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

hangulang์€ ์ด ๊ณต๋ฐฑ์„ ๋‹ค์Œ ์—ญํ• ๋กœ ์ฑ„์›๋‹ˆ๋‹ค:

  • ๊ฒ€์ฆ๋œ ํŒŒ์„œ๋ฅผ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ถ€๋ถ„์ ์ธ ์ž์ฒด ์žฌ๊ตฌํ˜„์ด ์•„๋‹ˆ๋ผ rhwp(ํ…Œ์ŠคํŠธ 1,100๊ฐœ ์ด์ƒ, HWP 5.0 + HWPX ์™„์ „ ์ง€์›) ์œ„์— ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ํ…์ŠคํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ตฌ์กฐ๋ฅผ ๋ณด์กดํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ DocLang exporter์—์„œ๋Š” ๋ณ‘ํ•ฉ/์ค‘์ฒฉ ํ‘œ๋ฅผ OTSL ํ† ํฐ์œผ๋กœ, ๊ฐœ์š” ์ˆ˜์ค€์€ ์‹ค์ œ <heading>์œผ๋กœ, ์ˆ˜์‹์€ LaTeX๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.
  • rhwp ํƒ€์ž…์„ ์ง์ ‘ ๋…ธ์ถœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ €์ˆ˜์ค€ parser model์„ ์†Œ๋น„์ž์—๊ฒŒ ๋„˜๊ธฐ์ง€ ์•Š๊ณ , ๋ณ€ํ™˜๊ธฐ/ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ์“ฐ๊ธฐ ์‰ฌ์šด ์•ˆ์ • IR๊ณผ ์ถœ๋ ฅ ๊ณ„์•ฝ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฒ„๋ฆฐ ๊ฒƒ์„ ๋ณด๊ณ ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ณ€ํ™˜์€ LossReport๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ, ํ˜ธ์ถœ์ž๋Š” ์–ด๋–ค ์ •๋ณด(๊ธ€๊ผด, ์ƒ‰์ƒ, ๊ฐ์ฃผ ๋“ฑ)๊ฐ€ ์†์‹ค๋๋Š”์ง€ ์ •ํ™•ํžˆ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค โ€” ์กฐ์šฉํ•œ ๋ฐ์ดํ„ฐ ์†์‹ค์ด ์—†์Šต๋‹ˆ๋‹ค.
  • ๊ฒ€์ฆ์„ ํ†ต๊ณผํ•ฉ๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ ์ฝ”ํผ์Šค ์ „์ฒด๊ฐ€ ๊ณต์‹ doclang validate์˜ XSD + Schematron ๊ฒ€์‚ฌ๋ฅผ 100% ํ†ต๊ณผํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ ๋ฒ”์œ„

hangulang์€ rhwp์˜ ๋Œ€์ฒด์ œ๊ฐ€ ์•„๋‹ˆ๋ผ, rhwp ์œ„์— ์˜ฌ๋ผ๊ฐ€๋Š” ์ œํ’ˆํ™” ๋ ˆ์ด์–ด์ž…๋‹ˆ๋‹ค.

๋ ˆ์ด์–ด ์ฑ…์ž„
rhwp HWP/HWPX ํŒŒ์ผ ํฌ๋งท ํŒŒ์‹ฑ, ๋‚ด๋ถ€ ๋ฌธ์„œ ๋ชจ๋ธ, ๋ Œ๋” ํŠธ๋ฆฌ ์ œ๊ณต
hangulang Rust core rhwp ๋ชจ๋ธ์„ semantic IR๋กœ ๋‚ฎ์ถ”๊ณ , ์ˆ˜์‹/ํ‘œ/์ด๋ฏธ์ง€/๊ฐ์ฃผ/์ขŒํ‘œ/loss๋ฅผ ์ •๊ทœํ™”
Exporters DocLang XML, semantic JSON payload, Markdown, asset references
hangulang-python Python wheel, Pythonic API, typed error, optional integrations(๊ณ„ํš)
Integrations Docling, LangChain, LlamaIndex ๋“ฑ ์™ธ๋ถ€ adapter(๊ณ„ํš)

rhwp-python์ด ์ €์ˆ˜์ค€ Python binding์ด๋ผ๋ฉด, hangulang-python์€ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์„œ ๋ณ€ํ™˜ API๋ฅผ ์ง€ํ–ฅํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ rhwp์˜ raw model/render tree๋ฅผ Python์— ๊ทธ๋Œ€๋กœ ๋…ธ์ถœํ•˜๊ธฐ๋ณด๋‹ค๋Š”, ์•ˆ์ •๋œ semantic payload์™€ export ๊ฒฐ๊ณผ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


์„ค์น˜

์ตœ์‹  ์•ˆ์ • ๋ฒ„์ „ Rust ํˆด์ฒด์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค(edition 2021, 1.94 ๊ธฐ์ค€ ๊ฐœ๋ฐœ).

rhwp๋Š” crates.io์— ๊ฒŒ์‹œ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฏ€๋กœ, ์žฌํ˜„์„ฑ์„ ์œ„ํ•ด ์ •ํ™•ํ•œ ์ปค๋ฐ‹์œผ๋กœ ๊ณ ์ •ํ•œ git ์˜์กด์„ฑ์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

[dependencies]
hangulang = { git = "https://github.com/myeolinmalchi/hangulang" }

๋นŒ๋“œ ์ฐธ๊ณ : rhwp์˜ ๋„ค์ดํ‹ฐ๋ธŒ ๋นŒ๋“œ๋Š” SVG/PDF ๋ Œ๋”๋ง ์Šคํƒ(svg2pdf, usvg, pdf-writer ๋“ฑ)์„ transitiveํ•˜๊ฒŒ ์ปดํŒŒ์ผํ•ฉ๋‹ˆ๋‹ค. ์ตœ์ดˆ ๋นŒ๋“œ์— ์•ฝ 35์ดˆ๊ฐ€ ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค. ์ด๋Š” ์•Œ๋ ค์ง„ upstream ๋น„์šฉ์ž…๋‹ˆ๋‹ค โ€” ๋กœ๋“œ๋งต ์ฐธ๊ณ .


๋น ๋ฅธ ์‹œ์ž‘

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

use hangulang::{convert, ConvertOptions};

let data = std::fs::read("document.hwp")?;
let outcome = convert(&data, &ConvertOptions::default())?;

println!("{}", outcome.xml);          // DocLang v0.6 XML
for entry in outcome.loss.iter() {    // ํ‘œํ˜„ํ•  ์ˆ˜ ์—†์—ˆ๋˜ ์ •๋ณด
    eprintln!("{:?} @ {}: {}", entry.kind, entry.location, entry.detail);
}

Semantic payload์™€ Markdown์€ DocLang XML์„ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ๊ฐ™์€ IR์—์„œ ์ง์ ‘ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค:

use hangulang::{convert_to_markdown, convert_to_payload, ConvertOptions};

let payload = convert_to_payload(&data, &ConvertOptions::default())?;
let markdown = convert_to_markdown(&data, &ConvertOptions::default())?;

serde feature๋ฅผ ์ผœ๋ฉด pretty JSON ๋ฌธ์ž์—ด๋„ ๋ฐ”๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

let json = hangulang::convert_to_json(&data, &ConvertOptions::default())?;

์ด๋ฏธ์ง€๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ self-contained data URI๋กœ ๋“ค์–ด๊ฐ€๋ฉฐ, ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌํ•ด์•ผ ํ•˜๋Š” ํŒŒ์ดํ”„๋ผ์ธ์—์„œ๋Š” ๋ฆฌ์†Œ์Šค ์ •์ฑ…์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

use hangulang::{convert, ConvertOptions, ResourcePolicy};

let opts = ConvertOptions {
    resource_policy: ResourcePolicy::asset_dir("assets"),
    ..Default::default()
};
let outcome = convert(&data, &opts)?;

for asset in outcome.assets {
    std::fs::write(format!("assets/{}", asset.path), asset.data)?;
}

์ถœ๋ ฅ API

API ์ถœ๋ ฅ ๋น„๊ณ 
convert DocLang XML, assets, LossReport ๊ธฐ์กด primary exporter
extract_semantic SirDocument, LocationMap, LossReport exporter๋ฅผ ์ง์ ‘ ๋งŒ๋“ค ๋•Œ ์‚ฌ์šฉ
convert_to_payload versioned SemanticPayload Python wrapper / integration์šฉ ์•ˆ์ • ๊ณ„์•ฝ
convert_to_json pretty JSON ๋ฌธ์ž์—ด serde feature ํ•„์š”
convert_to_markdown Markdown, assets, LossReport DocLang XML์„ ๊ฑฐ์น˜์ง€ ์•Š๋Š” ์ง์ ‘ exporter

CLI

cargo run --example convert_cli -- document.hwp --mode lean -o document.dclg.xml
usage: convert_cli <input.hwp|.hwpx> [--mode lean|preserve] [--location] [-o out.dclg.xml]

  --mode lean      ํ‘œ์ค€ DocLang ์š”์†Œ๋งŒ ์ถœ๋ ฅํ•˜๊ณ  ์†์‹ค์„ ๋ณด๊ณ  (๊ธฐ๋ณธ๊ฐ’)
  --mode preserve  ํ‘œํ˜„ ๋ถˆ๊ฐ€ํ•œ HWP ์†์„ฑ์„ ๋„ค์ž„์ŠคํŽ˜์ด์Šค <custom> ์š”์†Œ๋กœ ๋ณด์กด
  --location       <location> bounding box(๋ ˆ์ด์•„์›ƒ ์ขŒํ‘œ)๋„ ํ•จ๊ป˜ ์ถœ๋ ฅ
  -o <path>        ์ถœ๋ ฅ ํŒŒ์ผ (๊ธฐ๋ณธ๊ฐ’: <์ž…๋ ฅํŒŒ์ผ๋ช…>.dclg.xml)

์†์‹ค ๋ณด๊ณ  ์š”์•ฝ์€ stderr๋กœ ์ถœ๋ ฅ๋˜๋ฉฐ, ์˜ค๋ฅ˜ ์‹œ ์ข…๋ฃŒ ์ฝ”๋“œ๋Š” 0์ด ์•„๋‹™๋‹ˆ๋‹ค.


๋ชจ๋“œ

DocLang์€ ์˜๋„์ ์œผ๋กœ ๋ฏธ๋‹ˆ๋ฉ€ํ•ฉ๋‹ˆ๋‹ค(์˜๋ฏธ + ์ขŒํ‘œ + ์ฝ๊ธฐ ์ˆœ์„œ; ๊ธ€๊ผด/์ƒ‰์ƒ/์Šคํƒ€์ผ ์—†์Œ). HWP๋Š” ํ›จ์”ฌ ๋งŽ์€ ์ •๋ณด๋ฅผ ๋‹ด์Šต๋‹ˆ๋‹ค. ๋‘ ๋ชจ๋“œ๊ฐ€ ์ด ๊ฐ„๊ทน์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค:

๋ชจ๋“œ ์ถœ๋ ฅ ์‚ฌ์šฉ ์‹œ์ 
Lean (๊ธฐ๋ณธ๊ฐ’) ์ˆœ์ˆ˜ ํ‘œ์ค€ DocLang. ํ‘œํ˜„ ๋ถˆ๊ฐ€ ์ •๋ณด โ†’ LossReport์— ๊ธฐ๋ก ํ›„ XML์—์„œ ์ œ์™ธ. ํ† ํฐ ํšจ์œจ์ด ์ค‘์š”ํ•œ RAG / LLM ์ธ์ œ์Šค์ฒœ.
Preserve ํ‘œํ˜„ ๋ถˆ๊ฐ€ํ•œ HWP ์†์„ฑ์„ <custom ns="hwp:โ€ฆ">๋กœ ๋ณด์กด. ์ •๋ณด ์†์‹ค์ด ์—†์–ด์•ผ ํ•˜๋Š” ๋ผ์šด๋“œํŠธ๋ฆฝ / ์•„์นด์ด๋น™.
use hangulang::{convert, ConvertOptions, Mode};

let opts = ConvertOptions { mode: Mode::Preserve, ..Default::default() };
let outcome = convert(&data, &opts)?;

๋ ˆ์ด์•„์›ƒ ์ขŒํ‘œ (--location)

with_location์„ ํ™œ์„ฑํ™”ํ•˜๋ฉด, ๋ณ€ํ™˜๊ธฐ๋Š” rhwp::DocumentCore ๋ Œ๋” ํŠธ๋ฆฌ๋กœ ๊ฐ ํŽ˜์ด์ง€๋ฅผ ๋ฐฐ์น˜(layout)ํ•˜๊ณ , render node์˜ (section, paragraph, control) provenance๋ฅผ Hangulang IR์˜ Prov์™€ joinํ•ฉ๋‹ˆ๋‹ค. DocLang XML์—๋Š” <location value="N" resolution="512"/> ๋„ค ๊ฐœ(x_min, y_min, x_max, y_max)๋ฅผ ๋ถ™์ด๊ณ , semantic payload์—๋Š” page, bbox, resolution, status๋ฅผ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. ์ขŒํ‘œ๋Š” page-relative 0โ€“512 ๊ทธ๋ฆฌ๋“œ๋กœ ์ •๊ทœํ™”๋ฉ๋‹ˆ๋‹ค.

let opts = ConvertOptions { with_location: true, ..Default::default() };

๋น„ํ™œ์„ฑํ™” ์‹œ(๊ธฐ๋ณธ๊ฐ’) ์ถœ๋ ฅ์€ ์ขŒํ‘œ ์—†๋Š” ๋นŒ๋“œ์™€ byte-identical์ด๋ฉฐ, ํŽ˜์ด์ง€ ๋ ˆ์ด์•„์›ƒ ํŒจ์Šค๋Š” ์™„์ „ํžˆ ์ƒ๋žต๋ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ bbox๊ฐ€ ๋ถ™๋Š” ๋ฒ”์œ„:

IR ๋ธ”๋ก rhwp render node ์ฒ˜๋ฆฌ ๋ฐฉ์‹
๋ฌธ๋‹จ / ์ œ๋ชฉ / ๋ชฉ๋ก TextLine(section, para) ๊ฐ™์€ paragraph์˜ line box๋ฅผ ์ฒซ ํŽ˜์ด์ง€ ์•ˆ์—์„œ union
์ตœ์ƒ์œ„ ํ‘œ Table(section, para, control) control provenance๋กœ join; 1x1 wrapper flattening ์ผ€์ด์Šค ํ—ˆ์šฉ
๋ณธ๋ฌธ ์ด๋ฏธ์ง€ Image(section, para, control) ์…€/๋จธ๋ฆฌ๋ง/๊ผฌ๋ฆฌ๋ง ๋‚ด๋ถ€ ์ด๋ฏธ์ง€๋Š” ์ œ์™ธ
๋ณธ๋ฌธ ์ˆ˜์‹ Equation(section, para, control) ์…€/๊ฐ์ฃผ ๋‚ด๋ถ€ ์ˆ˜์‹์€ ์ œ์™ธ
๋จธ๋ฆฌ๋ง / ๊ผฌ๋ฆฌ๋ง Header / Footer group section์˜ header/footer control์— ์—ฐ๊ฒฐ

์—ฌ๋Ÿฌ ํŽ˜์ด์ง€์— ๊ฑธ์นœ ๋ธ”๋ก์€ ์ฒซ ํŽ˜์ด์ง€์— ๋‚˜ํƒ€๋‚œ segment๋งŒ bbox๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Semantic payload์—์„œ bbox๊ฐ€ ์—†์„ ๋•Œ๋Š” not_requested, no_provenance, unresolved, not_applicable ์ค‘ ํ•˜๋‚˜๋กœ ์ด์œ ๋ฅผ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.


์ปค๋ฒ„๋ฆฌ์ง€

DocLang์œผ๋กœ ๋งคํ•‘๋˜๋Š” ์š”์†Œ

HWP ์š”์†Œ DocLang ๋น„๊ณ 
๋ฌธ๋‹จ <text>
๊ฐœ์š” ์ œ๋ชฉ <heading level="1โ€“6"> ๊ธ€๊ผด ํฌ๊ธฐ ์ถ”์ธก์ด ์•„๋‹Œ ๊ฐœ์š” ์ˆ˜์ค€ ๊ธฐ์ค€
๋ชฉ๋ก(๋ฒˆํ˜ธ/๊ธ€๋จธ๋ฆฌํ‘œ) <list> / <ldiv> / <marker> ์ค‘์ฒฉ ์ง€์›
์ธ๋ผ์ธ ์„œ์‹ <bold> <italic> <underline> <strikethrough> <superscript> <subscript>
ํ•˜์ดํผ๋งํฌ <href uri="โ€ฆ"> ์•ต์ปค ๊ตฌ๊ฐ„์„ field_ranges๋กœ ์‹๋ณ„; ์›น/mailto/๋‚ด๋ถ€ ์ฑ…๊ฐˆํ”ผ
ํ‘œ OTSL (<fcel> <ched> <lcel> <ucel> <xcel> โ€ฆ) ๋ณ‘ํ•ฉ ยท ์ค‘์ฒฉ ์…€
์ˆ˜์‹ <formula> (LaTeX) EqEdit โ†’ LaTeX; ๋ณ€ํ™˜ ๋ˆ„๋ฝ ํ† ํฐ์€ ๋ณด๊ณ ๋จ
์ด๋ฏธ์ง€ <picture><src uri="โ€ฆ"/> ๊ธฐ๋ณธ๊ฐ’์€ ์ธ๋ผ์ธ base64; asset/URI ์ฐธ์กฐ ์ •์ฑ… ์ง€์›
๊ฐ์ฃผ <footnote>
๋จธ๋ฆฌ๋ง / ๊ผฌ๋ฆฌ๋ง <page_header> / <page_footer>
์ชฝ ๋‚˜๋ˆ„๊ธฐ <page_break/>
๋‹ค๋‹จ ์—ฐ์†์„ฑ <thread>
๋ ˆ์ด์•„์›ƒ ์ขŒํ‘œ (์˜ต์…˜) <location> / payload location rhwp render tree ๊ธฐ๋ฐ˜; ์œ„ ๋ฒ”์œ„ ์ฐธ๊ณ 

๋ฒ”์œ„ ์™ธ (v1)

  • ์ž…๋ ฅ: ์•”ํ˜ธํ™” ๋ฌธ์„œ(๊ฑฐ๋ถ€), ๋ฐฐํฌ์šฉ ๋ฌธ์„œ(rhwp๋Š” ํŒŒ์‹ฑ ๊ฐ€๋Šฅํ•˜๋‚˜ ์ •์ฑ…์ƒ ๊ฑฐ๋ถ€), HWP 3.x, ๋ ˆ๊ฑฐ์‹œ HWPML.
  • ์ถœ๋ ฅ: ์—ญ๋ณ€ํ™˜(DocLang โ†’ HWP); ๋ Œ๋”๋ง(SVG/PDF โ€” rhwp์˜ ์˜์—ญ).
  • ์ขŒํ‘œ: ๊ธ€์ƒ์ž ๋‚ด๋ถ€ ์ฝ˜ํ…์ธ , ๊ฐ์ฃผ/๋ฏธ์ฃผ ๋ณธ๋ฌธ, ์…€ ๋‚ด๋ถ€ ๊ฐ์ฒด์—๋Š” <location>์„ ๋ถ€์ฐฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์ด๋“ค์˜ ๋ž˜ํผ ํ‘œ์—๋Š” ๋ถ€์ฐฉ๋จ). Payload์—์„œ๋Š” ์ขŒํ‘œ๊ฐ€ ์—†๋Š” ์ด์œ ๋ฅผ not_requested, no_provenance, unresolved, not_applicable ์ƒํƒœ๋กœ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

์†์‹ค ๋ณด๊ณ 

Lean ๋ชจ๋“œ์—์„œ DocLang์ด ํ‘œํ˜„ํ•  ์ˆ˜ ์—†๋Š” ์ •๋ณด๋Š” ๋ชจ๋‘ LossEntry(kind, location, detail)๋กœ ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค. ์ข…๋ฅ˜์—๋Š” FontInfo, CharColor, NamedStyle, SectionSettings, FloatingObject, TextBox, TrackChanges, FormulaFallback, Caption, Other๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ๋ฌธ์„œ์˜ ๋ณด๊ณ ๊ฐ€ ๋น„์–ด ์žˆ์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์€, ์˜ˆ๋ฅผ ๋“ค์–ด ์ธ์ œ์Šค์ฒœ ํŒŒ์ดํ”„๋ผ์ธ์ด ํ•ด๋‹น ํŒŒ์ผ์„ ์กฐ์šฉํžˆ ๋ˆ„๋ฝ์‹œํ‚ค๋Š” ๋Œ€์‹  ๋” ํ’๋ถ€ํ•œ(์˜ˆ: VLM) ๊ฒฝ๋กœ๋กœ ๋ถ„๊ธฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.

DocLang ๋Œ€์‘ ์š”์†Œ๊ฐ€ ์—†๋Š” ์ผ๋ถ€ ์ปจํŠธ๋กค(๋ง๋ง(Ruby), ๊ธ€์ž๊ฒน์นจ(CharOverlap))์€ ํ…์ŠคํŠธ๋ฅผ ๋ฒ„๋ฆฌ์ง€ ์•Š๊ณ  ํ‰๋ฌธ ๋ธ”๋ก์œผ๋กœ ๊ตฌ์ œํ•˜๋ฉฐ, ์žƒ์€ ์˜๋ฏธ๋Š” LossEntry๋กœ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ดํผ๋งํฌ์™€ ์ธํ…์ŠคํŠธ ํ๋ฆ„ ๊ฐ์ฒด ์œ„์น˜๋Š” v2์—์„œ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚จ์€ ๋ณ€ํ™˜ ํ•œ๊ณ„๋กœ๋Š” ๋ฏธ์ฃผ ๋ณ„๋„ ํ‘œํ˜„, ์ขŒํ‘œ ๋ฏธ๋ถ€์ฐฉ ์˜์—ญ(๊ธ€์ƒ์ž/๊ฐ์ฃผ/์…€ ๋‚ด๋ถ€) ๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.


์•„ํ‚คํ…์ฒ˜

 HWP 5.0 (.hwp) โ”€โ”
                 โ”œโ”€โ–บ rhwp::parse_document โ”€โ–บ Hangulang Semantic IR โ”€โ”ฌโ”€โ–บ DocLang XML
 HWPX (.hwpx) โ”€โ”€โ”˜     (parser_adapter)      (rhwp ๋น„์˜์กด)             โ”œโ”€โ–บ semantic JSON payload
                                                                       โ”œโ”€โ–บ Markdown
                                                                       โ”œโ”€โ–บ resource assets / URIs
                                                                       โ””โ”€โ–บ Python API payload (planned)
                                                     โ–ฒ
                             eqedit ํŒจ์Šค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   (EqEdit script โ†’ LaTeX)
                             geometry ํŒจ์Šค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   (๋ Œ๋” ํŠธ๋ฆฌ โ†’ location/bbox, ์˜ต์…˜)

Pandoc์˜ reader โ†’ IR โ†’ writer ํŒจํ„ด์„ ๋ณธ๋œฌ 3๋‹จ๊ณ„ ํŒŒ์ดํ”„๋ผ์ธ์ž…๋‹ˆ๋‹ค. Semantic IR์€ rhwp ๋น„์˜์กด์ด๋ฉฐ, parser_adapter๋งŒ rhwp ํƒ€์ž…์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค โ€” upstream ๋ณ€๊ฒฝ์œผ๋กœ ๋ถ€ํ„ฐ ๋ณ€ํ™˜๊ธฐ๋ฅผ ๊ฒฉ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“ˆ ์—ญํ• 
parser_adapter rhwp Document โ†’ Semantic IR (์œ ์ผํ•œ rhwp ์˜์กด ๊ณ„์ธต)
ir rhwp ๋น„์˜์กด ๋ฌธ์„œ ๋ชจ๋ธ(๋ธ”๋ก, ์ธ๋ผ์ธ, ํ‘œ, ์ˆ˜์‹)
eqedit HWP EqEdit ์ˆ˜์‹ ์Šคํฌ๋ฆฝํŠธ โ†’ LaTeX
writer Semantic IR โ†’ DocLang v0.6 XML (OTSL ํ‘œ, ๋ชจ๋“œ, <location>)
payload Semantic IR โ†’ stable payload / JSON schema
markdown Semantic IR โ†’ Markdown
resources ์ด๋ฏธ์ง€ data URI, asset, URI prefix ์ •์ฑ…
loss LossReport ์ˆ˜์ง‘

๊ฐœ๋ฐœ

cargo test                                     # ๋‹จ์œ„ + ๊ณจ๋“  + ๋™๋“ฑ์„ฑ ํ…Œ์ŠคํŠธ
cargo test --features serde                    # JSON payload ์ง๋ ฌํ™” ๊ฒฝ๋กœ ํฌํ•จ
cargo test --features validator-integration    # ๊ณต์‹ doclang ๊ฒ€์ฆ๊ธฐ๊นŒ์ง€ ์‹คํ–‰
cargo clippy --all-targets                     # ๋ฆฐํŠธ (๊ฒฝ๊ณ  0 ๊ธฐ๋Œ€)

๋ฆด๋ฆฌ์ฆˆ ์ „ ์ ๊ฒ€๊ณผ crates.io publish blocker๋Š” docs/release.md์— ์ •๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ๊ธฐ ์—ฐ๋™

validator-integration ํ”ผ์ฒ˜๋Š” ๋ณ€ํ™˜๊ธฐ ์ถœ๋ ฅ์„ ๊ณต์‹ Python ๋ ˆํผ๋Ÿฐ์Šค ๊ฒ€์ฆ๊ธฐ๋กœ ํ†ต๊ณผ์‹œํ‚ต๋‹ˆ๋‹ค. ์ตœ์ดˆ 1ํšŒ ์„ค์ •:

python3 -m venv .venv
.venv/bin/pip install -r tests/requirements.txt   # doclang==0.6.0

venv๊ฐ€ ์—†์œผ๋ฉด ๊ฒ€์ฆ๊ธฐ ํ…Œ์ŠคํŠธ๋Š” ์ž๋™์œผ๋กœ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ์ฝ”ํผ์Šค

๊ณจ๋“  ํŒŒ์ผ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ๋Š” ์‹ค์ œ HWP/HWPX ๋ฌธ์„œ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. fixture์˜ ์ถœ์ฒ˜์™€ ๋ผ์ด์„ ์Šค๋Š” tests/fixtures/SOURCES.md์— ๋ฌธ์„œํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์˜๋„์ ์ธ ์ถœ๋ ฅ ๋ณ€๊ฒฝ ํ›„์—๋Š” UPDATE_GOLDEN=1 cargo test --test golden์œผ๋กœ ๊ณจ๋“ ์„ ์žฌ์ƒ์„ฑํ•˜์„ธ์š”.


๋กœ๋“œ๋งต

  • hangulang-python: Rust core๋ฅผ ๊ฐ์‹ผ Python wheel๊ณผ Pythonic API.
  • Docling optional adapter ๋˜๋Š” plugin.
  • LangChain/LlamaIndex document loader.
  • EqEdit โ†’ LaTeX ์‹ฌ๋ณผ ์ปค๋ฒ„๋ฆฌ์ง€ ํ™•๋Œ€ (ํ˜„์žฌ ๋ˆ„๋ฝ ํ† ํฐ์€ ๋ณด๊ณ ๋˜์ง€๋งŒ ์•„์ง ์™„์ „ํžˆ ๋ณ€ํ™˜๋˜์ง€๋Š” ์•Š์Œ).
  • CLI์˜ JSON/Markdown ์ถœ๋ ฅ ์˜ต์…˜๊ณผ asset directory ์“ฐ๊ธฐ.
  • ๊ธ€์ƒ์ž / ๊ฐ์ฃผ / ์…€ ๋‚ด๋ถ€ ์ฝ˜ํ…์ธ ์˜ ์ขŒํ‘œ ์ง€์›.
  • SVG/PDF ๋นŒ๋“œ ๋น„์šฉ์„ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•œ rhwp upstream parser-only ํ”ผ์ฒ˜.

๋ผ์ด์„ ์Šค

MIT. ์ž์„ธํ•œ ๋‚ด์šฉ์€ LICENSE๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

๋ณธ ํ”„๋กœ์ ํŠธ๋Š” ๋…๋ฆฝ์ ์ธ ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค. HWP/HWPX๋Š” ํ•œ๊ธ€๊ณผ์ปดํ“จํ„ฐ(Hancom Inc.)์˜ ํฌ๋งท์ด๋ฉฐ, ๋ณธ ํ”„๋กœ์ ํŠธ๋Š” ํ•œ์ปด๊ณผ ์ œํœด ๊ด€๊ณ„๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. DocLang์€ LF AI & Data Foundation์˜ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค. rhwp๋Š” ยฉ Edward Kim (MIT)์ž…๋‹ˆ๋‹ค.

About

Rust toolkit for parsing Korean HWP/HWPX documents and exporting semantic text, resources, and layout-aware payloads.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages