Node-REDのmustacheテンプレートで配列の要素にインデクス番号でアクセスする

mustache template
Raspberry Piを使ってハードウエアネタを書こうと思っていたのですが、アクセス数が少ないので早々に心が折れてます。ラズパイだからニッチなのは分かっていましたが・・・代わりにNode-REDをいじってます。これまたニッチ。以下、自分用メモです。

Node-REDではいろいろなAPIと連携した独自のAPIを簡単に作れそうです。
ブログパーツのようなものを作る時はテンプレートノードを使うと便利なようですが、配列へのアクセス方法がわからなかったので調べてみました。


前回、Raspberry Piにつないだ赤外線リモコンをNode-REDで動かせるようにしました。
関連記事:Google HomeとRaspberry PiのNode-REDで赤外線リモコンのコントロールをする

Node-REDはWEB上のAPIへ簡単にアクセスでき、JSONデータもお手軽に扱えるのがいいですね。そこで、APIが公開されているWEBサービスからデータを取得した独自のブログパーツも簡単に作れそうだと試しています。

基本はjavascriptなのは変わりません。ちょっと複雑なことをやろうと思うとfunctionノードでjavascriptを書きます。ならNode-REDなんて邪魔だな・・・と思ったりしますが、非同期で並列なリクエストやら処理関数を気にするのもめんどくさいです。やっぱNode-REDで試してみようとなりました。

できあいのライブラリの存在を知らなければ自分で一から書こうとしちゃうのはどんな言語でも一緒です。どんなノードがあるかちゃんと勉強しないといけません。でもそんなに使わないからなぁ・・・

最初の一歩でtemplateノードを使ってみます。いろいろ集めて加工した情報は最後にHTMLにして表示する事になるでしょう。そんな時に使うのがtemplateノードです。mustacheテンプレートを選択すると、静的なHTMLを記述しその一部にJSONデータを入れ込む事ができます。

例えば
{ "name" : "佐藤" ,"age": 25 }
というJSONデータのname要素を表示させるには{{payload.name}}というようにテンプレートに書いておきます。
テンプレートに次のように書いてみます。
<html>
<body>
<p>{{payload.name}}さんは {{payload.age}}才です。 </p>
</body>
</html>
するとテンプレートの出力はJSONデータの値に置き換わって、
<html>
<body>
<p>佐藤さんは 25才です。 </p>
</body>
</html>
となります。

Node-REDで動かしてみましょう。
Node-REDのFlowを作ってみました。
Test Flow 1
次のテキストをクリップボードにコピーしてNode-REDの"読み込み→クリップボード"へペーストしてください。
[{"id":"b9eaddb7.194f4","type":"inject","z":"ea42c97b.119448","name":"","topic":"","payload":"{ \"name\" : \"佐藤\" ,\"age\": 25 }","payloadType":"json","repeat":"","crontab":"","once":false,"x":210,"y":320,"wires":[["9ba92053.125e3"]]},{"id":"9ba92053.125e3","type":"template","z":"ea42c97b.119448","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n<body>\n<p>{{payload.name}}さんは {{payload.age}}才です。 </p>\n</body>\n</html>","output":"str","x":350,"y":320,"wires":[["e7a4ffec.e5cc2"]]},{"id":"e7a4ffec.e5cc2","type":"debug","z":"ea42c97b.119448","name":"","active":true,"console":"false","complete":"payload","x":510,"y":320,"wires":[]},{"id":"adc1dd07.e908e","type":"comment","z":"ea42c97b.119448","name":"{ \"name\" : \"佐藤\" ,\"age\": 25 }","info":"","x":200,"y":280,"wires":[]}]
一番左のボタン状の部分を押すとこのFlowが動きます。結果はデバッグタブに表示されます。
GETメソッドの応答として返せばブラウザに表示できますね。

これは便利だ! と調子に乗ってブログパーツもどきを作っているとすぐに壁にぶち当たりました。
配列はどうやって読むんだろう?

次のような配列があるとします。
[ { "name" : "佐藤" ,"age": 25 }, { "name" : "田中" ,"age": 18 } ]
配列だから{{payload[0].name}}だろう・・・
残念!動きません・・・ぇえ、どうするの?
こんな時は大元へ
mustacheのGitHubページを見ます。
janl/mustache.js | GitHub
どうやらsectionsという機能があるようです。配列をまとめて書き出してくれるようです。
{{#payload}}の様に配列の階層を指定して頭に"#"を付けます。sectionsの開始です。sectionsを閉じる時は{{/payload}}のように頭に"/"を付けます。ん、何を言ってるかわからないですね。実際に試しましょう。
今度はテンプレートを次のように書いてみましょう。
<html>
<body>
{{#payload}}
<p>{{name}}さんは {{age}}才です。 </p>
{{/payload}}
</body>
</html>
するとテンプレートの出力は次のようになります。
<body>
<p>佐藤さんは 25才です。 </p>
<p>田中さんは 18才です。 </p>
</body>
</html>
テンプレートには年齢の表示を1行しか書いてないのに二人とも表示されました。section内のテンプレートは配列要素すべてに繰り返されるようです。データベースから取ってきた値を表示するのに便利ですね。
これもFlowで実際に試してみましょう。
[{"id":"b4db33b6.55d8c","type":"inject","z":"ea42c97b.119448","name":"","topic":"","payload":"[ { \"name\" : \"佐藤\" ,\"age\": 25 }, { \"name\" : \"田中\" ,\"age\": 18 } ]","payloadType":"json","repeat":"","crontab":"","once":false,"x":210,"y":160,"wires":[["b677c617.89d298"]]},{"id":"b677c617.89d298","type":"template","z":"ea42c97b.119448","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n<body>\n{{#payload}}\n<p>{{name}}さんは {{age}}才です。 </p>\n{{/payload}}\n</body>\n</html>","output":"str","x":350,"y":160,"wires":[["a5436c4e.33bd8"]]},{"id":"a5436c4e.33bd8","type":"debug","z":"ea42c97b.119448","name":"","active":true,"console":"false","complete":"payload","x":510,"y":160,"wires":[]},{"id":"6e641f37.2495b","type":"comment","z":"ea42c97b.119448","name":"[ { \"name\" : \"佐藤\" ,\"age\": 25 }, { \"name\" : \"田中\" ,\"age\": 18 } ]","info":"","x":300,"y":120,"wires":[]}]

ところで全員の年齢は表示しなくていいんだけど・・・配列のインデックス番号で指定したい・・・また悩みます。配列の括弧[ ]は使えません。できないの⁉

またまた検索・・・おっこれか!
Accessing Array item by index in template #158
bobthecow commented on 25 Jan 2012
"{{ll.0}} and {{ll.1}} will work in most mustache implementations... haven't tried it in mustache.js though :)"
janl/mustache.js | GitHub
ドット"."のあとにインデックス番号を付けて配列要素にアクセスできます。
テンプレートを次のように変更してみましょう。sectionsは使わなくします。
<html>
<body>
<p>{{payload.0.name}}さんは {{payload.0.age}}才です。 </p>
</body>
</html>
次の表現でも動くようです。
<html>
<body>
{{#payload.1}}
<p>{{name}}さんは {{age}}才です。 </p>
{{/payload.1}}
</body>
</html>
処理結果はご自分でテンプレートを変更して試してみてください。

文字列の配列の時は{{.}}とします。

欲が出てmustacheテンプレートでいろいろな処理をしたくなりますね。JSONデータのキー自体の名称は取得できないようです。事前にJSONデータの構造をmustacheテンプレートに合わせて考える必要もあるでしょう。
いろいろ悩むくらいなら表示しやすいJSONデータへと加工するのが正しい使い方のようです。複雑な事はmustacheの役割ではありませんしできません。条件分岐やデータの加工などロジカルな制御が必要だったらテンプレートノードの前に終わらせましょう。

こういった抽象化したり切り分けた仕組みの概念が日本人は苦手ですよね。直接書いた方が簡単じゃん、となってしまいます。エクセル方眼紙みたいな逆向きのスキルは上手(?)ですけど。
ちょっと週間天気予報を表示させようと思っただけでしたが良い勉強になりました。


コメント

  1. ありがとうございました。ここの所ずっと悩んでいた問題が解決致しました。また、仰られている通り、"こんな時は大元へ"の言葉に改めて怠けていた自分を自戒する事ができました。感謝です!

    返信削除
    返信
    1. コメントありがとう、励みになります。mustacheの日本語情報増えないですね…

      削除

コメントを投稿

最近のコメント

Threaded Recent Comments will be here.