형식 무관 IR
DocumentIR은 Office Oxide가 형식 간에 놓는 구조적 다리입니다. .docx, .xlsx, 레거시 .ppt를 열어도 같은 형태가 돌아옵니다 — 섹션 목록과, 각 섹션 내부의 타입 있는 요소(제목, 단락, 표, 목록, 이미지) 시퀀스.
IR은 to_html, save_as, 레거시 → OOXML 변환을 받칩니다. 다운스트림 파이프라인 — 검색 인덱스, RAG 청커, 커스텀 렌더러 — 에도 가장 적합한 접점입니다. 형식별로 6개의 스키마가 아닌 하나의 스키마만 처리하면 되니까요.
IR 읽기
Rust
use office_oxide::Document;
let doc = Document::open("report.docx")?;
let ir = doc.to_ir();
for section in &ir.sections {
println!("{:?}", section.title);
for el in §ion.elements {
// el은 Element enum — Heading, Paragraph, Table, List, Image, ...
}
}
Python
from office_oxide import Document
with Document.open("report.docx") as doc:
ir = doc.to_ir()
for section in ir["sections"]:
print(section.get("title"))
for el in section["elements"]:
kind = el["kind"] # "Heading" | "Paragraph" | "Table" | "List" | "Image"
JavaScript
using doc = Document.open('report.docx');
const ir = doc.toIr();
for (const section of ir.sections) {
for (const el of section.elements) {
// el.kind: "Heading" | "Paragraph" | "Table" | "List" | "Image"
}
}
Go
import "encoding/json"
irJSON, _ := doc.ToIRJSON()
var ir struct {
Sections []struct {
Title *string `json:"title"`
Elements []json.RawMessage `json:"elements"`
} `json:"sections"`
}
_ = json.Unmarshal([]byte(irJSON), &ir)
C#
using System.Text.Json;
using var doc = Document.Open("report.docx");
using var ir = JsonDocument.Parse(doc.ToIrJson());
foreach (var section in ir.RootElement.GetProperty("sections").EnumerateArray())
{
// ...
}
스키마
형태는 의도적으로 작고 안정적입니다.
{
"sections": [
{
"title": "선택적 섹션 제목", // string | null
"elements": [
{ "kind": "Heading", "level": 1, "text": "..." },
{ "kind": "Paragraph", "runs": [
{ "text": "Hello ", "bold": false, "italic": false },
{ "text": "world", "bold": true, "italic": false }
] },
{ "kind": "List", "ordered": true, "items": ["one", "two"] },
{ "kind": "Table", "rows": [
["A1", "B1"],
["A2", "B2"]
] },
{ "kind": "Image", "filename": "image1.png", "data": "<base64>" }
]
}
]
}
형식별 매핑:
| 형식 | 섹션 경계 | 비고 |
|---|---|---|
| DOCX | <w:sectPr>마다 한 섹션(없으면 본문 전체) |
제목은 w:pStyle로 키잉 |
| XLSX | 워크시트마다 한 섹션 | title = 시트 이름; 사용 범위마다 Table 요소 한 개 |
| PPTX | 슬라이드마다 한 섹션 | title = 슬라이드 제목 자리표시자; 노트는 마지막 단락으로 부착 |
| DOC / XLS / PPT | OOXML 대응품과 같은 형태 | 레거시 CFB 파이프라인을 통해 파싱 |
IR을 쓰는 이유
- 한 번 빌드하고 여러 번 렌더. DOCX, XLSX, PPTX를 같은 형태로 변환하고 단일 검색/청킹 파이프라인으로 처리.
- 형식 변경을 견디는 LLM 컨텍스트. 소스가
.doc에서.docx로 옮겨가도 스키마는 흔들리지 않습니다. save_as로 라운드트립. IR을 편집하고 어떤 지원 형식으로든 새 문서를 씁니다.
use office_oxide::create::create_from_ir;
use office_oxide::DocumentFormat;
create_from_ir(&ir, DocumentFormat::Docx, "out.docx")?;
직렬화
Rust의 DocumentIR은 Serialize / Deserialize(serde 경유)를 derive합니다. Python의 to_ir()은 일반 dict을 반환합니다(이미 JSON 직렬화 가능). Node, Go, C#, C 바인딩은 to_ir_json() / ToIRJSON() / ToIrJson()으로 JSON 문자열을 노출합니다.
더 보기
- Markdown 추출 — LLM 친화적 텍스트
- HTML 추출 — 스타일이 들어간 출력이 필요할 때
- 변환: 레거시 → OOXML — 내부적으로 IR 사용