「TAURI」でExcelのデータを読み書きしてWebページに表示してみよう

2024年4月2日(火)
大西 武 (オオニシ タケシ)
第12回の今回は「TAURI」で「Rust」の「umya-spreadsheet」クレートを使って「Excel」の「xlsx」ファイルを読み書きし、Webページに表示するところまでを解説します。

バックエンドから50音を取得する

ここから、ようやくRustでバックエンドをコーディングしていきます。まだバックエンドでなければできない機能ではないのですが、バックエンドからフロントエンドに50音を取得してみます。

「main.js」と「main.rs」を記述して「$ cargo-tauri dev」コマンドで実行し、テーブル表左上の「開く」ボタンをクリックすれば、図1と同じ50音がテーブル表に表示されます。バックエンドから送られたデータですが、まだxlsxファイルのデータではありません。

JavaScriptからバックエンドを呼び出す

TAURIコマンド「get_data」関数を呼び出して、5列10行の数値とともに50音の文字列配列を取得します。その3つを取得したら初期データと同様に「setData」関数に「列数」引数と「行数」引数と「セルの文字列配列」引数を渡します。

・「src」→「main.js」ファイルのサンプルコード
1(前略)
2// xlsxファイルの読み込み
3function openXlsx() {
4  // Rustから50音データを取得
5  (async() => {
6    let data = await invoke("get_data",{});
7    setData(data[0],data[1],data[2]);
8  })();
9}

【サンプルコードの解説】
非同期で「get_data」メッセージを送って戻り値を「data」変数に取得します。
「setData」関数にdata配列を3つの引数にして渡します。

Rustからフロントエンドへ50音を返す

先ほどJavaScriptから呼び出したTAURIコマンド「get_data」関数はRustでバックエンドにコーディングします。この関数で(5列,10行,50音の文字列配列)タプルを取得できます。この関数は後ほど「50音.xlsx」ファイルに保存する際にも使います。

・「src-tauri」→「src」→「main.rs」ファイルのサンプルコード
01#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
02// 50音を取得するTAURIコマンド関数
03#[tauri::command]
04fn get_data() -> (u32,u32,Vec<String>) {
05  let data = vec![
06    "あ".to_string(),"い".to_string(),"う".to_string(),"え".to_string(),"お".to_string(),
07    "か".to_string(),"き".to_string(),"く".to_string(),"け".to_string(),"こ".to_string(),
08    "さ".to_string(),"し".to_string(),"す".to_string(),"せ".to_string(),"そ".to_string(),
09    "た".to_string(),"ち".to_string(),"つ".to_string(),"て".to_string(),"と".to_string(),
10    "な".to_string(),"に".to_string(),"ぬ".to_string(),"ね".to_string(),"の".to_string(),
11    "は".to_string(),"ひ".to_string(),"ふ".to_string(),"へ".to_string(),"ほ".to_string(),
12    "ま".to_string(),"み".to_string(),"む".to_string(),"め".to_string(),"も".to_string(),
13    "や".to_string()," ".to_string(),"ゆ".to_string()," ".to_string(),"よ".to_string(),
14    "ら".to_string(),"り".to_string(),"る".to_string(),"れ".to_string(),"ろ".to_string(),
15    "わ".to_string()," ".to_string(),"を".to_string()," ".to_string(),"ん".to_string(),];
16  (5,10,data)
17}
18// メイン関数
19fn main() {
20  //TAURIコマンド関数の登録
21  tauri::Builder::default()
22    .invoke_handler(tauri::generate_handler![get_data])
23    .run(tauri::generate_context!())
24    .expect("error while running tauri application");
25}

【サンプルコードの解説】
「get_data」関数で(5,10,50音)タプルを返します。
メイン関数のtauriビルダーでTAURIコマンド「get_data」関数を登録します。

バックエンドで50音をxlsxファイルに保存

ここからバックエンドならではの機能として「umya-spreadsheet」クレートを使った実装をしていきます。手を抜くならサンプルのxlsxファイルを用意してダウンロードしてもらえば良いのですが、せっかくなのでxlsxファイルに書き出す処理も併せて解説したいと思います。

「save_data」関数で50音を「50音.xlsx」ファイルに保存するのですが、この関数はTAURIコマンド関数にはしません。メイン関数の最初で呼び出して実行するだけです。

いったん、これを「$ cargo-tauri dev」コマンドで実行して「../50音.xlsx」ファイルを作成しておいてください。ただしこのファイルパスはリリースビルドする際にはあまり行儀がよくありません。ファイルダイアログで保存先を指定できるように改造すると良いでしょう。

・「src-tauri」→「src」→「main.rs」ファイルのサンプルコード
01#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
02// クレート
03use std::path::Path;
04use umya_spreadsheet::*;
05// xlsxファイルに50音を保存する関数
06fn save_data() {
07  let mut book = new_file();
08  let _ = book.new_sheet("Sheet1");
09  let (col,row,data) = get_data();
10  let mut i = 0;
11  for r in 1..=row {
12    for c in 1..=col {
13      book.get_sheet_by_name_mut("Sheet1").unwrap().get_cell_mut((c, r)).set_value(data[i].clone());
14      i += 1;
15    }
16  }
17  let path = Path::new("../50音.xlsx");
18  let _ = writer::xlsx::write(&book, path);
19}
20(中略)
21// メイン関数
22fn main() {
23  //xlsxファイルに保存
24  save_data();
25  tauri::Builder::default()
26    .invoke_handler(tauri::generate_handler![get_data])
27    .run(tauri::generate_context!())
28    .expect("error while running tauri application");
29}

【サンプルコードの解説】
「path」と「umya_spreadsheet」クレートを読み込みます。
save_data関数でブックを新規作成し、そのブックに"Sheet1"という名前のシートを新規作成します。50音をget_data関数から取得します。"Sheet1"の(c列,r行)タプルのセルにdata配列から取得した値をセットします。ブックを「../50音.xlsx」ファイルに保存します。
メイン関数でsave_data関数を呼び出します。

ファイルダイアログでxlsxファイルを読み込む

次のサンプルコードのように「main.js」「main.rs」ファイルを記述したら、やっとテーブル左上の「開く」ボタンをクリックすれば、ファイルダイアログでExcel独自形式のxlsxファイルが読み込まれ、Webページにテーブル表が表示されるようになります。

図3のように50音だけでなく、たいていのxlsxファイルのセルの文字列が読み込めます。ただしA~Zの26列までしかヘッダーは対応していませんが、行数はメモリの許す限り読み込めると思います。

図3:50音以外のxlsxファイルを読み込んだ画面

JavaScriptでファイルダイアログの表示

ファイルダイアログ(open関数)はフロントエンドのJavaScriptで表示します。xlsxファイルを開いたらバックエンドのTAURIコマンド「open_data」関数にそのファイル名を引数に渡して呼び出し、Excelデータから抜き出したデータを取得します。

・「src」→「main.js」ファイルのサンプルコード
01const { invoke } = window.__TAURI__.tauri;
02// ファイルダイアログ
03const { open,save } = window.__TAURI__.dialog;
04// tableタグ
05let table;
06(中略)
07// xlsxファイルの読み込み
08function openXlsx() {
09/*
10  (async() => {
11    let data = await invoke("get_data",{});
12    setData(data[0],data[1],data[2]);
13  })();
14*/
15  // Rustからxlsxファイルを読み込む
16  open({
17    filters: [
18      { name: 'Excel', extensions: ['xlsx'] },
19    ],
20  }).then(async file => {
21    let data = await invoke("open_data", { path: file });
22    setData(data[0],data[1],data[2]);
23  });
24}

【サンプルコードの解説】
TAURIのJavaScriptの「open」関数を読み込みます。
コメントアウトした50音の取得のコードを削除します。
open関数でファイルの種類をxlsx拡張子だけにしてファイルダイアログを開き、選択したファイルを「open_data」メッセージで読み込んで表示します。

Rustでxlsxファイルの読み込み

JavaScriptから渡された"open_data"メッセージでTAURIコマンド関数が呼ばれ、ファイルダイアログのファイル名のxlsxファイルを開いて(列数、行数、セルの文字列の配列)タプルを取得できます。Rustではタプルは「()」で囲みますが、JavaScriptでは配列もタプルも配列と同じ「[]」で囲みます。

・「src-tauri」→「src」→「main.rs」ファイルのサンプルコード
01(前略)
02// xlsxファイルを開くTAURIコマンド関数
03#[tauri::command]
04fn open_data(path: &str) -> (u32,u32,Vec<String>) {
05  let path = Path::new(path);
06  let mut book = reader::xlsx::read(path).unwrap();
07  let ws = book.get_active_sheet_mut();
08  let (col,row) = ws.get_highest_column_and_row();
09  let mut data = Vec::new();
10  for r in 1..=row {
11    for c in 1..=col {
12      data.push(ws.get_value((c,r)));
13    }
14  }
15  (col,row,data)
16}
17// メイン関数
18fn main() {
19//  save_data(); 削除
20  // TAURIコマンド関数の登録
21  tauri::Builder::default()
22    .invoke_handler(tauri::generate_handler![get_data,open_data])
23    .run(tauri::generate_context!())
24    .expect("error while running tauri application");
25}

【サンプルコードの解説】
「open_data」関数の引数のxlsxファイルをブックに読み込み、アクティブなシートをws(ワークシート)変数に代入します。最大列数と最大行数を取得して、その各(列,行)タプルのセルの文字列を「data」変数に追加します。(列数,行数,data配列)タプルを返します。
メイン関数でコメントアウトした「save_data」関数の呼び出しを削除し、tauriビルダーにTAURIコマンドopen_data関数を登録します。

おわりに

今回は、Excel独自形式のxlsxファイルを読み書きしてWebページのテーブル表にセルの文字列を表示してみました。クレートを使えばExcelデータをWebページで表示することも可能です。このような感じでクレートを使って様々なデータをWebページで表示してみると良いでしょう。

著者
大西 武 (オオニシ タケシ)
1975年香川県生まれ。大阪大学経済学部経営学科中退。プログラミング入門書など30冊以上を商業出版する作家。Microsoftで大賞やNTTドコモでグランプリなど20回以上全国区のコンテストに入賞するアーティスト。オリジナルの間違い探し「3Dクイズ」が全国放送のTVで約10回出題。
https://profile.vixar.jp

連載バックナンバー

開発言語技術解説
第15回

「TAURI」でデータベースを使ってみよう

2024/5/10
第15回の今回は「TAURI」でオープンソースのデータベース「SQLite3」を使用して、テーブル表に表示する解説をしていきます。
開発言語技術解説
第14回

「TAURI」で気象庁の「CSVデータ」を解析する

2024/5/1
第14回の今回は気象庁のWebサイトから指定した地域の1年間の気象データをダウンロードして「TAURI」で解析していきます。
開発言語技術解説
第13回

「TAURI」で「簡易RSSリーダー」を開発してみよう

2024/4/16
第13回の今回は「TAURI」で「RSSフィード」を読み込んでWebページに一覧表示し、リンクのページを開くための新規ウィンドウを作成するところまでを解説します。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています