10
8

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 5 years have passed since last update.

xlsx-populateで取得した値がややこしいことになってた時に文字列だけを取り出す方法

Last updated at Posted at 2018-08-21

RedmineとJavaScriptに身も心も捧げる8amjpです。

xlsx-populate

さて、私の職場でもRedmineを導入したんですけど、今まで使っていたエクセル形式の帳票も継続して使わなきゃならんという事で、node.jsとxlsx-populateというライブラリを使用して、エクセル帳票のインポート/エクスポートツールを作成して運用しているんです。
このxlsx-populate、JavaScriptからエクセルファイルを非常に高い精度で読み書きできる素晴らしいツール。しかもエクセルのインストールは不要です。ありがたいですねー。

ところが、運用しているうちに一つの問題にぶつかりました。

ややこしい値

workbook.sheet("Sheet1").cell("A1").value();

xlsx-populateでは、こんな感じでセルの値を取得します。わかりやすいですね。
で、通常は数値やら文字列やら、とにかく単純な値が返ってくるんですけど。たまに、セルの一部の文字だけ赤字にしたり大きくしたりフォント変えたり、と余計な事する人いるじゃないですか。そういうセルの値を取得すると、ものすごくややこしいデータが返ってきます。
どれくらいややこしいかというと、こんな感じ。

[
  {"name":"r","attributes":{},"children":[
    {"name":"t","attributes":{},"children":["テキスト1"]}
  ]},
  {"name":"r","attributes":{},"children":[
    {"name":"rPr","attributes":{},"children":[
      {"name":"sz","attributes":{"val":11},"children":[]},
      {"name":"rFont","attributes":{"val":"MSPゴシック"},"children":[]},
      {"name":"family","attributes":{"val":3},"children":[]},
      {"name":"charset","attributes":{"val":128},"children":[]}
    ]},
    {"name":"t","attributes":{},"children":["テキスト2"]}
  ]},
  {"name":"r","attributes":{},"children":[
    {"name":"rPr","attributes":{},"children":[
      {"name":"sz","attributes":{"val":11},"children":[]},
      {"name":"rFont","attributes":{"val":"MS Pゴシック"},"children":[]},
      {"name":"family","attributes":{"val":3},"children":[]},
      {"name":"charset","attributes":{"val":128},"children":[]}
    ]},
    {"name":"t","attributes":{},"children":["テキスト3"]}
  ]},

  /* 中略 */

  {"name":"phoneticPr","attributes":{"fontId":2},"children":[]}
]

なんすかこれ。
まあ、エクセルはエクセルで、指定されたとおり忠実に再現しないといけないわけで、こんな律儀なデータになるんですけど。エクセルには罪はないんですけど。
でも、必要なのは単純なテキストだけなので、その部分だけ取り出したいんです。さて、どうしましょう。

こたえ

必要な文字列は、「nameプロパティの値がtであるオブジェクトのchildrenプロパティの配列内」に入ってます。
で、そのオブジェクトは、「nameプロパティの値がrであるオブジェクトのchildrenプロパティの配列内」に入ってます。
なので、それを上手いこと取り出せばいいんですね。
さあ、JavaScriptが誇る配列操作用の関数、filtermap関数の出番ですよ。

var value = workbook.sheet("Sheet1").cell("A1").value();
if (Array.isArray(value)) value = value.filter(prop => prop.name == 'r').map(r => r.children.filter(prop => prop.name == 't')[0].children[0]).join();

書いてて気持ちいいですねー、このコード。
特に細かく解説しませんけど、今まで説明したことをやってるだけですよ。

というわけで、xlsx-populateで取得した値がややこしいことになってた時に文字列だけを取り出す方法でした。

2019/9/13 追記

v1.20.0から仕様が変わりまして、RichTextオブジェクトがサポートされ、リッチテキストを使用しているセルの値を取得するとRichTextオブジェクトが返るようになりました。

const RichText = require('xlsx-Populate').RichText;
let value = workbook.sheet(0).cell('A1').value();
let text = value instanceof RichText ? value.text() : value;

とすれば、リッチテキストだろうがプレーンテキストだろうが文字列のみを取得できます。

……のはずなのですが、instanceof RichTextとしてもなぜかfalseが返ってきてしまうので、さしあたり

let text = value instanceof Object ? value.text() : value;

として逃げてます。

10
8
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
10
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?