Google スプレッドシートを『装飾も含めて』 HTML で見たい?
Google スプレッドシートを HTML で見るという記事を前に書いた。
これをもう一歩進めて見た目も反映させたいという話がお仕事中に持ち上がったので書いたため、共有しておく。
つまり、この見た目をそのまま HTML として出力したい、という話である。
書き方
前提知識
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 には そう<strong>しょく</strong>なし が格納される
実際に書いたソースコード
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>
公開する
前回の記事の末尾に手順を書いているのでそちらで。