Skip to content

テーブルの抽出

Office OxideはテーブルをIRの第一級要素として扱います。DOCXの <w:tbl>、XLSXの各範囲、PPTXの <a:tbl> はすべて型付きの Table { rows: [[cell, ...]] } オブジェクトとして返されます。1つのループで3つのフォーマットすべてに対応できます。

ドキュメント内のすべてのテーブルを走査する

Rust

use office_oxide::Document;
use office_oxide::ir::Element;

let doc = Document::open("report.docx")?;
let ir = doc.to_ir();

for section in &ir.sections {
    for el in &section.elements {
        if let Element::Table(t) = el {
            for row in &t.rows {
                println!("{row:?}");
            }
        }
    }
}

Python

from office_oxide import Document

with Document.open("report.docx") as doc:
    ir = doc.to_ir()

for section in ir["sections"]:
    for el in section["elements"]:
        if el["kind"] == "Table":
            for row in el["rows"]:
                print(row)

JavaScript

using doc = Document.open('report.docx');
const ir = doc.toIr();

for (const section of ir.sections) {
  for (const el of section.elements) {
    if (el.kind === 'Table') {
      for (const row of el.rows) {
        console.log(row);
      }
    }
  }
}

Go

doc, err := officeoxide.Open("report.docx")
if err != nil { log.Fatal(err) }
defer doc.Close()

irJSON, _ := doc.ToIRJSON()
var ir struct {
    Sections []struct {
        Elements []struct {
            Kind string     `json:"kind"`
            Rows [][]string `json:"rows"`
        } `json:"elements"`
    } `json:"sections"`
}
json.Unmarshal([]byte(irJSON), &ir)

for _, section := range ir.Sections {
    for _, el := range section.Elements {
        if el.Kind == "Table" {
            for _, row := range el.Rows {
                fmt.Println(row)
            }
        }
    }
}

C#

using OfficeOxide;
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())
{
    foreach (var el in section.GetProperty("elements").EnumerateArray())
    {
        if (el.GetProperty("kind").GetString() != "Table") continue;
        foreach (var row in el.GetProperty("rows").EnumerateArray())
        {
            Console.WriteLine(string.Join(" | ", row.EnumerateArray().Select(c => c.GetString())));
        }
    }
}

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 ir_json with your JSON lib, then walk sections -> elements,
       keeping every element whose "kind" == "Table" and iterating its "rows" */
    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) {
      if (el.kind === 'Table') {
        for (const row of el.rows) {
          console.log(row);
        }
      }
    }
  }
} finally {
  doc.free();
}

XLSX:シート範囲ごとのテーブル

スプレッドシートでは、各セクションがワークシートに対応し、テーブルは検出された使用済み範囲にマッピングされます。空のセルは空文字列として出力され、結合セルは左上の値が展開されて残りは空白になります。

Python

import csv
from office_oxide import Document

with Document.open("budget.xlsx") as doc:
    ir = doc.to_ir()

for section in ir["sections"]:
    sheet_name = section.get("title", "Sheet")
    out_path = f"{sheet_name}.csv"
    with open(out_path, "w", newline="") as f:
        w = csv.writer(f)
        for el in section["elements"]:
            if el["kind"] == "Table":
                for row in el["rows"]:
                    w.writerow(row)

セルごとのより詳細なアクセス(数式、結合セル、名前付き範囲)が必要な場合は、フォーマット固有のAPIを使用してください:

Python

with Document.open("budget.xlsx") as doc:
    xlsx = doc.as_xlsx()
    for sheet in xlsx.sheets():
        print(sheet.name(), sheet.dimensions())

DOCX:段落と混在するテーブル

IRは段落とテーブルのソース上の順序を保持するため、文書のフローを再現できます:

Python

from office_oxide import Document

with Document.open("report.docx") as doc:
    ir = doc.to_ir()

for section in ir["sections"]:
    for el in section["elements"]:
        if el["kind"] == "Heading":
            print(f"\n## {el['text']}")
        elif el["kind"] == "Paragraph":
            print(" ".join(r["text"] for r in el["runs"]))
        elif el["kind"] == "Table":
            for row in el["rows"]:
                print("|", " | ".join(row), "|")

PPTX:スライドセクション内のテーブル

各スライドは独立したセクションです。セクションを反復することでスライドごとのコンテキストを取得できます:

Python

with Document.open("deck.pptx") as doc:
    ir = doc.to_ir()

for i, section in enumerate(ir["sections"], 1):
    for el in section["elements"]:
        if el["kind"] == "Table":
            print(f"slide {i}: {len(el['rows'])}×{len(el['rows'][0])} table")

文字列ではなくセルの型が必要な場合

IRのテーブル表現ではセルが文字列に平坦化されます。XLSXで数値・テキスト・真偽値を区別するには、フォーマット固有のアクセサを使用してください:

Python

with Document.open("budget.xlsx") as doc:
    xlsx = doc.as_xlsx()
    for sheet in xlsx.sheets():
        for cell in sheet.cells():
            print(cell.address(), cell.value(), cell.value_type())

関連情報