7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Google Spreadsheet のセルを装飾を含めて HTML にする

Last updated at Posted at 2023-01-09

Google スプレッドシートを『装飾も含めて』 HTML で見たい?

Google スプレッドシートを HTML で見るという記事を前に書いた。

これをもう一歩進めて見た目も反映させたいという話がお仕事中に持ち上がったので書いたため、共有しておく。

つまり、この見た目をそのまま HTML として出力したい、という話である。
image.png

書き方

前提知識

Range#getRichTextValue で装飾情報を取得

Google Apps Script の Range クラスには getRichTextValue なる関数がある。

これの返り値はRichTextValue クラスであり、その名の通りテキストスタイルを含むセルの情報が格納されるものである。よって、この情報を HTML にすればセルの内容を HTML にすることができる。

getRuns() でセルの内容を分割した値を取得

RichTextValue が取得できたので早速装飾情報を取りたいが、装飾情報は入れ子になっていたりして複雑である。セルを文字列が装飾されている単位ごとに分割するには getRuns関数を用いる。これの返り値は RichTextValue の配列となる。
この配列に格納されている値を一つ一つ HTML 化し、連結することでセルの内容を HTML にすることができる。

TextStyle クラスから装飾情報の詳細を取得する

RichTextValue クラスの getTextStyle の帰り値はTextStyle クラスである。これを使うことで RichTextValue クラスが持つ装飾情報の詳細を取得できる。

このクラスが持つ以下の関数を用いて装飾情報を取得する。

  • getFontFamily
  • getFontSize
  • getForegroundColorObject
  • isBold
  • isItalic
  • isStrikethrough
  • isUnderline

文字列のサニタイズ

上述の例 B1 のセルは そう<strong>しょく</strong>なし となっており、このまま出力すると「そうしょくなし」と出力される。しかし、これは「そう<strong>しょく</strong>なし」と出力されてほしい。
今回は次のようにしてサニタイズした。

const textTemplate = HtmlService.createTemplate('<?= text ?>');
textTemplate.text = "そう<strong>しょく</strong>なし";
const text = textTemplate.evaluate().getContent();
// text には そう&lt;strong&gt;しょく&lt;/strong&gt;なし が格納される

実際に書いたソースコード

JavaScript

function convertRunToHtml(run) {
  const textStyleMethods = {
    getFontFamily:            (result)=>{
      if(result) { decoration['font-family'] = result; }
    },
    getFontSize:              (result)=>{
      if(result) { decoration['font-size'] = `${result}px`; }
    },
    getForegroundColorObject: (result)=>{
      decoration['color'] = result.asRgbColor().asHexString();
    },
    isBold:                   (result)=>{
      if(result) { decoration['font-weight'] = 'bold'; }
    },
    isItalic:                 (result)=>{
      if(result) { decoration['font-style'] = 'italic'; }
    },
    isStrikethrough:          (result)=>{
      if(result) { decoration['text-decoration'] = decoration['text-decoration'] ? `${decoration['text-decoration']} line-through` : 'line-through';}
    },
    isUnderline:              (result)=>{
      if(result) { decoration['text-decoration'] = decoration['text-decoration'] ? `${decoration['text-decoration']} underline` : 'underline';}
    }
  };
  const decoration = {};
  const textStyle = run.getTextStyle();
  const link = run.getLinkUrl();
  const textTemplate = HtmlService.createTemplate('<?= text ?>');
  textTemplate.text = run.getText();
  const text = textTemplate.evaluate().getContent().replaceAll('\n', '<br/>');

  for(var method in textStyleMethods) {
    textStyleMethods[method](textStyle[method]());
  }
  const style = [];
  for(var key in decoration) {
    style.push(`${key}:${decoration[key]};`);
  }
  if(link) {
    return `<a href="${link}" style="${style.join('')}">${text}</a>`;
  } else {
    return `<span style="${style.join('')}">${text}</span>`;
  }
}

function convertCellToHtml(cell) {
  const result = [];
  const runs = cell.getRichTextValue().getRuns();
  for(var k = 0; k < runs.length; k++) {
    result.push(convertRunToHtml(runs[k]));
  }
  return `<td style="background-color:${cell.getBackground()};">${result.join('')}</td>`;
}

function getTable() {
  const range = SpreadsheetApp.getActiveSheet().getDataRange();
  const rawLength = range.getLastRow() + 1;
  const columnLength = range.getLastColumn() + 1;

  const result = [];
  for(var i = 1; i < rawLength; i++) {
    const rawResult = [];
    for(var j = 1; j < columnLength; j++) {
      rawResult.push(convertCellToHtml(range.getCell(i, j)))
    }
    result.push(rawResult);
  }
  return result;
}

function doGet() {
  return HtmlService.createTemplateFromFile('template.html').evaluate();
}

HTML のテンプレート

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <table border="1" id="table">
      <? 
        const data = getTable();
        data.forEach((row)=>{
      ?>
        <tr>
          <? row.forEach((col)=>{ ?>
            <?!= col ?>
          <? }); ?>
        </tr>
      <? }); ?>
    </table>
  </body>
</html>

公開する

前回の記事の末尾に手順を書いているのでそちらで。

得られた出力

image.png

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?