【Java】スプレッドシートの表をHTML化する
IT技術

概要
Googleスプレッドシートに記載されている表をHTMLとして生成することができるツールの開発について記事にしました。
前提
言語はJavaです。そしてスプレッドシートの内容を読み込み、JavaクラスにマッピングするツールとしてXlsMapperというライブラリを使用します。詳細な前提条件はリンク先に記載あるのでそちらを確認してください。
[完成イメージ]
スプレッドシート

↓
HTML

ちなみにプロジェクトのディレクトリ構成は以下になります。

解説
スプレッドシートの内容をJavaに読み込ませるには手元のPCにxlsxファイルをダウンロードしてくる必要があります。今回は以下のようなスプレッドシートをsample.xlsxとして"com.sample"直下に配置します。

そしてsample.xlsxからデータを読み込み、取得したデータを元にHTMLを生成するメインの処理を記述したコードが以下になります。(packageやimportの記載は省略)
SampleConverter.java
1public class SampleConverter {
2  public static void main(String[] args) {
3    var xlsMapper = new XlsMapper();
4
5    // 配置したSample.xlsxからデータを取得
6    try {
7      var sheet = xlsMapper.load(
8        new FileInputStream("src/main/java/com/sample/sample.xlsx"),
9        SampleSheet.class
10      );
11      // 取得したデータをもとにhtmlを生成
12      convertToHtml(sheet);
13    } catch (IOException e) {
14      throw new RuntimeException(e);
15    }
16  }
17
18  /*
19   * Excelから取得したデータを元にHTMLを生成
20   *
21   * @param sheet sample.xlsxから取得したデータ
22   */
23  private static void convertToHtml(SampleSheet sheet) {
24
25    // テンプレートエンジンの初期化
26    var engine = initializeTemplateEngine();
27
28    // テンプレートに渡すコンテキストを作成
29    var context = new Context();
30
31    // 表データを1行分ずつ格納したリストを作成
32    var recordList = new ArrayList<LinkedHashMap>();
33    for (SampleRecord record : sheet.getRecords()) {
34      createRecordList(recordList, record);
35    }
36
37    // 表データをcontextに設定
38    context.setVariable("recordList", recordList);
39
40    // templateからhtmlを生成
41    try {
42      var writer = new FileWriter("result/sample.html");
43      engine.process("sample-template", context, writer);
44    } catch (IOException e) {
45      throw new RuntimeException(e);
46    }
47  }
48
49  /**
50   * テンプレートエンジンを初期化
51   *
52   * @return テンプレートエンジン
53   */
54  private static TemplateEngine initializeTemplateEngine() {
55    var templateEngine = new TemplateEngine();
56    var resolver = new ClassLoaderTemplateResolver();
57    resolver.setTemplateMode("HTML");
58    resolver.setSuffix(".html");
59    templateEngine.setTemplateResolver(resolver);
60    return templateEngine;
61  }
62
63  /**
64   * 1行ごとの表データを格納したリストを作成
65   *
66   * @param recordList 1行ごとの表データを格納するリスト
67   * @param record 1行分の表データ
68   * @return 1行ごとの表データを格納したリスト
69   */
70  private static void createRecordList(
71    ArrayList<LinkedHashMap> recordList, SampleRecord record) {
72    var columnDataMap = new LinkedHashMap();
73
74    // SampleRecordクラスのフィールド情報を取得
75    var fields = record.getClass().getDeclaredFields();
76
77    // 各フィールド名と値の組み合わせをMapにつめる
78    for (Field field : fields) {
79      field.setAccessible(true);
80      try {
81        columnDataMap.put(field.getName(), field.get(record));
82      } catch (IllegalAccessException e) {
83        throw new RuntimeException(e);
84      }
85    }
86    // 作成したMapをListにつめる
87    recordList.add(columnDataMap);
88  }
89}SampleSheet.java
1@XlsSheet(name = "sample")
2@Data
3public class SampleSheet {
4  @XlsHorizontalRecords(headerAddress = "A1")
5  List records;
6}見慣れないアノテーションが2つありますね。
@XlsSheetはxlsxファイルの指定されたシートを読み込んでJavaクラスにマッピングしてくれます。今回はsampleシートを読み込むため、nameプロパティの値がsampleとなっています。
もう一つの@XlsHorizontalRecordsは水平方向に連続する行をCollection(List, Map等)にマッピングしてくれます。ヘッダーが横並びの表をマッピングしたい場合にこのアノテーションを使用します。(他の表形式に対応するアノテーションもあるのでドキュメントを参照してみてください)
SampleRecord.java
1@Data
2public class SampleRecord {
3  @XlsColumn(columnName = "ID")
4  private int id;
5
6  @XlsColumn(columnName = "Name")
7  private String name;
8
9  @XlsColumn(columnName = "Age")
10  private int age;
11
12  @XlsColumn(columnName = "Gender")
13  private String gender;
14}このクラスでもxlsMapperのアノテーションが使用されています。@XlsColumnはcolumnName属性で指定したカラム名に紐づくセルの値をフィールドにマッピングしてくれます。
以下の図でいうとcolumnName属性にカラム名である"ID" を指定するとidフィールドに数字の1がマッピングされます。

ここまでスプレッドシートから取得したデータを加工しhtmlファイルにレコード情報を渡す準備ができました。最後にデータの渡し先になるsample-template.htmlの内容が以下になります。
1<!DOCTYPE html>
2<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
3<head>
4    <meta charset="UTF-8" />
5    <title>Sample</title>
6    <style>
7        table {
8            border-collapse: collapse;
9        }
10        th, td {
11            border: 1px solid #dddddd;
12            text-align: left;
13            padding: 8px;
14        }
15        th {
16            text-align: center;
17            background-color: #f2f2f2;
18        }
19    </style>
20</head>
21<body>
22<div>
23    <table>
24        <thead>
25            <tr>
26                <th>ID</th>
27                <th>Name</th>
28                <th>Age</th>
29                <th>Gender</th>
30            </tr>
31        </thead>
32        <tbody>
33            <tr th:each="record: ${recordList}">
34                <td th:each="cell, iterStat : ${record}" th:text="${cell.value}"></td>
35            </tr>
36        </tbody>
37    </table>
38</div>
39</body>
40</html>Java側からデータを受け取って繰り返し処理をするため、Thymeleafを使用しています。
必要なコードは以上になります。あとはSampleConverter.javaのmainメソッドを実行するとresultディレクトリ配下にsample.htmlが生成されます。

ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ

2022年6月入社。雑食系エンジニア。







