フォーマット非依存の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 列挙型 — 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())
{
// ...
}
C
int err = 0;
OfficeDocumentHandle *doc = office_document_open("report.docx", &err);
char *ir_json = office_document_to_ir_json(doc, &err); /* DocumentIR as JSON */
if (ir_json) {
/* parse with your JSON lib — sections[].elements[].kind: "Heading" | ... */
office_oxide_free_string(ir_json);
}
office_document_free(doc);
WASM
import { WasmDocument } from 'office-oxide-wasm';
const data = new Uint8Array(await (await fetch('/report.docx')).arrayBuffer());
const doc = new WasmDocument(data, 'docx');
try {
const ir = doc.toIr(); // JS object, schema == Rust DocumentIR
for (const section of ir.sections) {
for (const el of section.elements) {
// el.kind: "Heading" | "Paragraph" | "Table" | "List" | "Image"
}
}
} finally {
doc.free();
}
スキーマ
形状は意図的にシンプルかつ安定しています。
{
"sections": [
{
"title": "Optional section 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> ごとに1セクション(なければ本文全体) |
見出しはw:pStyleで識別 |
| XLSX | ワークシートごとに1セクション | title = シート名;使用範囲ごとにTable要素1つ |
| PPTX | スライドごとに1セクション | title = スライドタイトルのプレースホルダー;ノートは末尾の段落として付加 |
| DOC / XLS / PPT | OOXMLの対応形式と同一の形状 | レガシーCFBパイプラインで解析 |
IRを使う理由
- 一度構築、多様なレンダリング。 DOCX、XLSX、PPTXを同一の形状に変換して、単一の検索・チャンキングパイプラインを走らせられます。
- フォーマット変更に耐えるLLMコンテキスト。 ソースドキュメントが
.docから.docxに移行してもスキーマが変わりません。 save_asでのラウンドトリップ。 IRを編集し、サポートされた任意のフォーマットで新規ドキュメントを書き出せます。
Rust
use office_oxide::create::create_from_ir;
use office_oxide::DocumentFormat;
create_from_ir(&ir, DocumentFormat::Docx, "out.docx")?;
シリアライズ
RustのDocumentIRはserde経由でSerialize / Deserializeを導出しています。Pythonのto_ir()は通常のdictを返します(すでにJSONシリアライズ可能)。Node・Go・C#・CバインディングはJSON文字列をto_ir_json() / ToIRJSON() / ToIrJson()で公開しています。
関連項目
- Markdown抽出 — LLM向けテキスト用
- HTML抽出 — スタイル付き出力が必要な場合
- 変換:レガシー→OOXML — 内部でIRを使用