LoginSignup
9
13

More than 5 years have passed since last update.

Node-RED の change/switch ノードで使える JSONata の README.md を訳してみた

Last updated at Posted at 2018-11-15

Node-RED の ソース を眺めていたところ JSONata ライブラリを見つけました。JSON を操作する簡易言語のようで、なかなか面白いです。

Node-RED で change ノードや switch ノードの値の選択で「JSONata式」がありますが、この処理を実装しているのがこのライブラリのようですね。
image.png

まずは GitHub 上の README.md をざっと訳して、試してみましょう。2018年11月15日に version 1.5.4 を参照しています。

README.md of jsonata

クエリと変換のための言語 JSONata の JavaScript 実装です。

インストール

npm install jsonata

使い方

Node.js の場合:

var jsonata = require("jsonata");

var data = {
  example: [
    {value: 4},
    {value: 7},
    {value: 13}
  ]
};
var expression = jsonata("$sum(example.value)");
var result = expression.evaluate(data);  // 24 を返す

【訳注】上記の例は地味なんですが、JSONata 式でワイルドカード * などが使えて、最後の部分を以下のように変えても同じ動作をするって楽しくないですか?

var expression = jsonata("$sum(*.value)");
var result = expression.evaluate(data);  // これも 24 を返す

Web の場合:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>JSONata test</title>
    <script src="lib/jsonata.js"></script>
    <script>
      function greeting() {
        var json = JSON.parse(document.getElementById('json').value);
        var result = jsonata('"Hello, " & name').evaluate(json);
        document.getElementById('greeting').innerHTML = result;
      }
    </script>
  </head>
  <body>
    <textarea id="json">{ "name": "Wilbur" }</textarea>
    <button onclick="greeting()">Click me</button>
    <p id="greeting"></p>
  </body>
</html>

【訳注】上記の html をブラウザ表示したのが以下で、「Click me」ボタンを押すと下にメッセージが表示されます。
image.png

jsonataは、generators などの ES2015 機能を使用します。 これらの機能がないブラウザでは、lib/jsonata-es5 を使用してください。

API

jsonata(str)

文字列 str を JSONata 式として解析し、コンパイルされた JSONata expression オブジェクトを返します。

var expression = jsonata("$sum(example.value)");

式が有効な JSONata でない場合、構文エラーに関する情報を含む Error がスローされます。たとえば、次のような:

{
  code: "S0202",
  stack: "...",
  position: 16,
  token: "}",
  value: "]",
  message: "Syntax error: expected ']' got '}'"
}

expression には3つのメソッドがあります:

expression.evaluate(input[, bindings[, callback]])

オブジェクト input に対してコンパイルされた JSONata expression を実行し、その結果を新しいオブジェクトとして返します。

var result = expression.evaluate({example: [{value: 4}, {value: 7}, {value: 13}]});
// 変数 result には 24 が代入される

inputJSON.parse() から返されるような JavaScript 値でなければなりません。input が JSON 文字列として解析できなかった(循環、関数を含む、など)場合、expression の動作は定義されていません。resultJSON.stringify() が正しく解釈できる JavaScript 値です。

bindings は、存在する場合、バインドされる変数名と値(関数を含む)を含みます:

jsonata("$a + $b()").evaluate({}, {a: 4, b: () => 78});
// 82 を返す

expression.evaluate() は実行時エラーをスローする可能性があります:

var expression = jsonata("$notafunction()"); // JSONata の書式としては問題ない
expression.evaluate({}); // エラーをスローする

Error には、ランタイムエラーの情報が含まれています。たとえば、次のようになります:

{
  code: "T1006",
  stack: "...",
  position: 14,
  token: "notafunction",
  message: "Attempted to invoke a non-function"
}

callback(err, value) 関数が指定されている場合、expression.evaluate()undefined を返し、expression は非同期に実行され、Error または結果が callback 関数に渡されます。

jsonata("7 + 12").evaluate({}, {}, (error, result) => {
  if(error) {
    console.error(error);
    return;
  }
  console.log("Finished with", result);
});
console.log("Started");

// "Started" と表示され、次に "Finished with 19" と表示される

xpression.assign(name, value)

さきほどの例で bindings が動作する方法と同様に、expression 内の名前に値を永続的にバインドします。expression 変更し undefined を返します。JSONata expression ファクトリを作成する際に便利です。

var expression = jsonata("$a + $b()");
expression.assign("a", 4);
expression.assign("b", () => 1);

expression.evaluate({}); // 5

expression.evaluate() を呼び出す際、bindings 引数が次の値を拘束することに注意してください:

expression.evaluate({}, {a: 109}); // 110

【訳注】上記の式はその前で定義した expression を使いまわしているので、jsonata("$a + $b()") という JSONata 定義と、assign("b", () => 1) という値定義の影響が残っている、ということでしょうかね。

expression.registerFunction(name, implementation[, signature])

expression 内の名前に関数を永続的にバインドします。

var expression = jsonata("$greet()");
expression.registerFunction("greet", () => "Hello world");

expression.evaluate({}); // "Hello world"

これは expression.assign または expression.evaluatebindings を使用して行うことができますが、expression.registerFunction では関数 signature を指定できます。これは予想される入力引数の型と、関数の戻り値の型を JSONata に伝える簡潔な文字列です。 JSONata は、実際の入力引数型が一致しない場合(戻り値の型はまだチェックされていない)、実行時エラーを発生させます。

var expression = jsonata("$add(61, 10005)");
expression.registerFunction("add", (a, b) => a + b, "<nn:n>");

expression.evaluate({}); // 10066

【訳注】上記の <nn:n> という signatures を <n:n> と変更して実行してみたところ、確かに Error がスローされるのが確認できました。
image.png

関数 signatures は次のように指定されます:

関数 signature 構文

関数 signature は <params:return> という形式の文字列です。params は型シンボルを順に並べたものであり、それぞれが入力引数の型を表します。return は戻り値の型を表す単一の型シンボルです。

型の記号は次のように機能します:

シンプルな型:

  • b - Boolean (真偽値)
  • n - number (数値)
  • s - string (文字列)
  • l - null

複雑な型:

  • a - array (配列)
  • o - object (オブジェクト)
  • f - function (関数)

ユニオン型:

  • (sao) - 文字列、配列、オブジェクトのいずれか
  • (o) - o と同じ
  • u - (bnsl) と同等
  • (bnsl) - 真偽値、数値、文字列、null のいずれか
  • j - 任意の JSON 型で、(bnsloa) と同等
  • (bnsloa) - 真偽値、数値、文字列、null、オブジェクト、配列のいずれか、ただし関数は含まない
  • x - 任意の型で、(bnsloaf) と同等

パラメータ型:

  • a<s> - 文字列の配列
  • a<x> - 任意の型の配列

組込み JSONata 関数の signature の例をいくつか示します:

  • $count の signature は <a:n> で、配列を受け取り、数値を返す
  • $append の signature は <aa:a> で、2つの配列を受け取り、配列を返す
  • $sum の signature は <a<n>:n> で、数値の配列を受け取り、数値を返す
  • $reducev<fa<j>:j> で、reducer 関数の f と JSON オブジェクトの配列 a<j> を受け取り、JSON オブジェクトを返す

それぞれの型の記号には、オプションが適用されている場合もあります。

  • + - この型の引数が1つ以上
    • 例) $zip の signature は <a+>で、配列、もしくは2つの配列、もしくは3つの配列…(以下略) を受け取る
  • ? - オプション(省略可能)の引数
    • 例) $join の signature は <a<s>s?:s> で、文字列の配列と、そして接続に使用する文字列(デフォルト値は空)を受け取り、文字列を返す
  • - - この引数がない場合は、コンテキスト値("focus")を使用します
    • 例) $length の signature は <s-:n> で、これは1つの引数を指定して $length(OrderID) のように呼び出せますが、これは OrderID.$length() と同じです

More information

Contributing

このリポジトリに貢献する方法の詳細については、CONTRIBUTING.md を参照してください。

というわけで

JSONata なかなか面白いですね。使える 関数 の数も多いようで、JSON 形式のデータを扱う Node-RED フローで function ノードの数を激減できそうな気がしてきます。

JSONata の言語ガイド良い説明ページ を訳してみたので、こちらも参考にしてみてください。

いろいろ試してみたいとおもいます!また何か面白そうな情報がありましたら紹介しますね。

ではでは。

9
13
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
9
13