Private Node “Excel→JSON変換ノード” をさらに使いやすくする

Private Node でExcel → JSON変換ノードを使いやすくしてみる」の記事では、 ExcelファイルをJSONオブジェクトに変換するPrivate Node ”Xlsx2Json”をバージョンアップして、msgオブジェクトとして入力されるExcelファイルをJSONに変換できるようにしました。

さらに”Xlsx2Json”ノードが使いやすくなるように、今回の記事ではちょっとしたバージョンアップを行います。

目次

はじめに

この記事は、以下の2つの記事の続編です。

最初の記事では、enebularのPrivate Node機能の使い方を説明しました。
2つ目の記事では、最初の記事で作ったPrivate Nodeをバージョンアップしながら、Private Nodeのバージョン管理機能を紹介しました。

3つ目のこの記事では、enebularの機能からは少し離れて、Node-REDのノードを作成する上でのちょっとしたノウハウについて紹介します。ここで紹介するノウハウは、「ノードを作るときはmsgオブジェクトで設定できるようにしておく」というものです。詳細は、以下の記事で説明します。

また、ここまで3回の記事で”Xlsx2Json”ノードの開発について説明してきましたが、ここで一旦区切りということにして、バージョンを1.0.0にします。

Node-REDノードのコンフィグレーションの問題

Node-REDでノードの設定をする場合、通常はフローエディタを開いてノードの設定画面を開いて設定していきます。

しかし、設定変更の度に、フローエディタを開くのは手間がかかります。また、フローエディタから設定変更する方法では、フローの実行中に動的に設定を変更することができません。こういった問題の解決策の1つとして、msgオブジェクトを使ってノードの設定ができるようにする方法があります。
一例として、File-inノードを見てみましょう。ノードのヘルプには、以下のような記述があります。

filename
読み出し対象のファイル名をノードに設定していない場合、このプロパティでファイルを指定できます

つまり、フローエディタでファイル名を設定していない場合(下図のFilenameが空の場合)は、msgオブジェクトのfilenameプロパティ(msg.filename)に設定されたファイル名のファイルから読み込みを行うということです。したがって、msg.filenameを変更することで、フローの動作中に読み込み対象のファイルを変更することができます。

“Xlsx2Json” ノードでも、同じようにmsg.filenameプロパティを使って読み込むExcelファイルを変更できるようにしてみましょう。下図のようなイメージです。使い方は、File-inノードにかなり近くなりました。

“Xlsx2Json” の変更内容

具体的な”Xlsx2Json” ノードの変更内容を確認しましょう。

従来の仕様

まずは、前回の記事までの仕様を確認します。

  1. FilenameにExcelファイルのファイル名(パス)が指定されていた場合は、Excelファイルを読み込んでJSONオブジェクトに変換する
  2. Filenameが空の場合は、入力される msg オブジェクトの msg.payload をExcelファイルとして読み込んで、JSONオブジェクトに変換する

新しい仕様

次に、今回の記事での新しい仕様です。

  1. FilenameにExcelファイルのファイル名(パス)が指定されていた場合は、指定されたExcelファイルを読み込んでJSONオブジェクトに変換する
  2. msg.filenameにExcelファイルのファイル名(パス)が指定されていた場合は、指定されたExcelファイルを読み込んでJSONオブジェクトに変換する
  3. Filenameとmsg.filenameの両方が空の場合は、入力される msg オブジェクトの msg.payload をExcelファイルとして読み込んで、JSONオブジェクトに変換する

前回の記事との違いは、2番が追加されていることです。
優先順位は、1 > 2 > 3 の順番です。つまり、1と2の設定がない場合のみ、msg.payloadをExcelファイルとして扱います。

ソースコードの修正

それでは、ソースコードを修正します。

package.json

バージョンアップするので、package.jsonのバージョンを0.2.0→1.0.0に変更しておきましょう。

{
“name”: “enebular-privatenode-contrib-xlsx2json”,
“version”: “1.0.0”,
“description”: “”,

javascript

新しいソースコードは以下のようになります。11行目〜17行目が今回の変更部分です。
元のバージョンでは、node.filename(フローエディタで設定するFilenameの項目)だけを確認していましたが、これが設定されていない場合に、msg.filenameをチェックするようにしています。
どちらも設定されていなければ、msg.payloadをExcelファイルとして扱います。

const XLSX = require('xlsx');

module.exports = function(RED) {
    function Xlsx2JsonNode(config) {
        RED.nodes.createNode(this,config);
        this.filename = config.filename;
        const node = this;        

        node.on('input', function(msg, send, done) {
            send = send || function() { node.send.apply(node,arguments) };
            let filename = null;
            if (node.filename) {
                filename = node.filename;
            } else if (msg.filename) {
                filename = msg.filename;
            }
            if (filename) {
                try {
                    const workbook = XLSX.readFile(filename);
                    msg.payload = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
                }
                catch (err) {
                    msg.payload = {
                        "error": err,
                        "filename": filename, 
                    };
                }
            } else {
                try {
                    const workbook = XLSX.read(msg.payload, {type:"buffer"});
                    msg.payload = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
                }
                catch (err) {
                    msg.payload = {
                        "error": err,
                        "filename": filename, 
                    };
                }
            }
            node.send(msg);
            if (done) {
                done();
            }
        });
    }
    RED.nodes.registerType("xlsx2json",Xlsx2JsonNode);
}

Private Node のバージョン管理

新しいバージョンの”Xlsx2Json”ノードをenebularに登録する前に、既存のバージョンに名前をつけておきます。「Private Node でExcel → JSON変換ノードを使いやすくしてみる」の記事中の “Private Node のバージョン管理” の章を参考にして作業します。元のバージョンには、”0_2_0″としておきます。

新バージョンの登録

ソースコードのあるフォルダーで [ターミナル|シェル|コマンドプロンプト] から、以下のコマンドを実行して、新しいバージョンの”Xlsx2Json”ノードのパッケージを作成します。

npm pack

enebular-privatenode-contrib-xlsx2json-1.0.0.tgz というファイルが出来ます。ここでも、「Private Node でExcel → JSON変換ノードを使いやすくしてみる」の記事中の “Private Node のバージョン管理” の章を参考にして、”Xlsx2Json”ノード バージョン1.0.0を登録します。

“Xlsx2Json” を使ってみる

新バージョンの “Xlsx2Json” ノードを使って、以下のようなフローを作ってみました。フローからエクスポートしたJSONファイルも添付しておきますので、興味のある方はフローエディタにインポートして、使ってみてください。

このフローは、以下のような動作をします。

  1. Http Requestノード(図の”Download Excel File”)でダウンロードしたExcelファイルをFileノード(図の”Save Excel File”)で保存する
  2. 1で保存したExcelファイルをXlsx2Jsonノードで読み込んでJSONに変換し、Debugノードで出力する

詳しく説明していきます。

フローは、Injectノード(図の”Timestamp”)で始まります。フローを動作させる場合は、このノードをクリックしてください。
次にChangeノード(図の”Set Filename”)で、msg.filenameプロパティにファイル名 “test.xlsx” を設定します。このファイル名でExcelファイルが保存されます。

続いてHttp Requestノード(図の”Download Excel File”)でExcelファイルをダウンロードします。ダウンロード対象のURLは https://www.mext.go.jp/content/20201221-mxt_syogai03-000010378_1.xlsx です。ダウンロードしたファイルは、Fileノード(図の”Save Excel File”)で保存します。このとき、Changeノードで設定した msg.filenameプロパティ(”test.xlsx”)がファイル名として利用されます。

Excelファイルの保存が終わると、Xlsx2Jsonノードが呼び出されます。Excelファイルを読み出してJSONに変換します。このときも、Changeノードで設定した msg.filenameプロパティ(”test.xlsx”)がファイル名として利用されます。
変換されたJSONオブジェクトは、Splitノードで分割されて、Debugノードに出力されます。Splitノードでオブジェクトを細かく分割するのは、Debugノードの出力が読みやすくなるようにするためです。

以上が、図のフローの動作です。あまり役に立つフローではありませんが、msgオブジェクトを使って、ノードの設定を変えるというのがどういうことか、わかってもらえるのではないでしょうか。

[{"id":"5554444f.0eef5c","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"9d08eb63.43f558","type":"xlsx2json","z":"5554444f.0eef5c","name":"","filename":"","x":560,"y":220,"wires":[["a7441d02.0d52"]]},{"id":"6a087103.8934c","type":"debug","z":"5554444f.0eef5c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":910,"y":220,"wires":[]},{"id":"a7441d02.0d52","type":"split","z":"5554444f.0eef5c","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":730,"y":220,"wires":[["6a087103.8934c"]]},{"id":"b95f6ef4.47ec1","type":"http request","z":"5554444f.0eef5c","name":"Download Excel File","method":"GET","ret":"bin","paytoqs":false,"url":"https://www.mext.go.jp/content/20201221-mxt_syogai03-000010378_1.xlsx","tls":"","persist":false,"proxy":"","authType":"","x":340,"y":140,"wires":[["de647117.93f74"]]},{"id":"81f73788.75bb38","type":"inject","z":"5554444f.0eef5c","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":60,"wires":[["d53fac50.7b32d"]]},{"id":"de647117.93f74","type":"file","z":"5554444f.0eef5c","name":"Save Excel File","filename":"","appendNewline":true,"createDir":false,"overwriteFile":"true","encoding":"none","x":580,"y":140,"wires":[["9d08eb63.43f558"]]},{"id":"d53fac50.7b32d","type":"change","z":"5554444f.0eef5c","name":"Set Filename","rules":[{"t":"set","p":"filename","pt":"msg","to":"test.xlsx","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":310,"y":60,"wires":[["b95f6ef4.47ec1"]]}]

おわりに

今回の記事では、Node-REDのノードを作成する場合の、ちょっとしたノウハウとして、msgオブジェクトでノードを設定できるようにする様子を記事にしてみました。
このノウハウは割とベーシックなものだと思いますが、あまり紹介記事を見かけません。自分でノードを開発する方は、こんなノウハウも少し気にしていただけると良いのではないかと思います。