これは、セカンドライフ 技術系 Advent Calendar 2013向けに書かれた記事です。LSLにJSONを扱う関数が追加されたので、今回はそれを紹介します。
JSONとは
JSONはJavascriptの記法で書かれたデータなのですが、いろんなプログラミング言語にJSONを扱うためのライブラリがあるので、さまざまなプログラム間でデータをやりとりするときに使われています。
こんなかんじでオブジェクトと配列の組み合わせでJSONは構成されます。
{ "a" : 1, "b" : true }
[ "c", 3, false ]
[ "c", 3, false, { "a" : 1, "b" : true } ]
LSLには「値を1つずつ処理する方法」「JSONをリストに一括で変換する方法」の、2通りのやり方が用意されています。一気に紹介しようと思ったのですが、意外と長くなってしまったので、今回は値を1つずつ処理する方法を紹介します。
llJsonGetValue
string llJsonGetValue(string json, list specifiers)
JSONから指定したパスにある値を文字列として取得します。第一引数に対象のJSONを指定して、第二引数のListでパスを指定します。
string value1 = llJsonGetValue("{ \"a\" : 1, \"b\" : true }", ["a"]);
llOwnerSay(value1);
string value2 = llJsonGetValue("[ \"c\", 3, false, { \"a\" : 1, \"b\" : true } ]", [3, "b"]);
llOwnerSay(value2);
2つめの例をみるとわかるように、リストにパスとなる値を書いていくことで深い位置にある値もとってくることができます。しかし、うまくTRUEと表示されてくれません。LSLには定数として「TRUE」が用意されてるんですが、これって単に数値の1の置き換えでしかないので、実は真の意味で真偽値を表す定数ってないんですね。そこで、JSONの真偽値を表すために「JSON_TRUE」「JSON_FALSE」が追加されています。
string value1 = llJsonGetValue("{ \"a\" : 1, \"b\" : true }", ["b"]);
if(value1 == JSON_TRUE)
{
llOwnerSay("TRUEを取得しました");
}
定数は他にもあります。
string value1 = llJsonGetValue("{ \"a\" : 1, \"b\" : null }", ["b"]);
if(value1 == JSON_NULL)
{
llOwnerSay("NULLを取得しました");
}
string value2 = llJsonGetValue("{ \"a\" : 1, \"b\" : null }", ["c"]);
if(value2 == JSON_INVALID)
{
llOwnerSay("不正な操作です");
}
llJsonSetValue
string llJsonSetValue(string json, list specifiers, string value)
当然値をセットする関数もあります。第一引数に対象のJSONを指定して、第二引数のListでパスを指定、第三引数でセットする値を指定します。返り値は値が更新されたJSONです。
string value1 = llJsonSetValue("{ \"a\" : 1, \"b\" : true }", ["a"], "2");
llOwnerSay(value1);
string value2 = llJsonSetValue("[ \"c\", 3, false, { \"a\" : 1, \"b\" : true } ]", [3, "a"], "\"2\"");
llOwnerSay(value2);
string value3 = llJsonSetValue("{ \"a\" : 1, \"b\" : true }", ["a"], "{\"c\":1,\"d\":2}");
llOwnerSay(value3);
string value4 = llJsonSetValue("{ \"a\" : 1, \"b\" : true }", ["c"], "3");
llOwnerSay(value4);
数値と数字の文字列が区別されたり、オブジェクトをセットできたり、けっこう自由度が高いです。また特殊な定数を使った便利な操作も用意されています。
string value1 = llJsonSetValue("{ \"a\" : 1, \"b\" : true }", ["a"], JSON_NULL);
llOwnerSay(value1);
string value2 = llJsonSetValue("[ \"c\", 3, false, { \"a\" : 1, \"b\" : true } ]", [JSON_APPEND], "5");
llOwnerSay(value2);
string value3 = llJsonSetValue("[ \"c\", 3, false, [ \"a\", \"b\"] ]", [3, JSON_APPEND], "6");
llOwnerSay(value3);
string value4 = llJsonSetValue("{ \"a\" : 1, \"b\" : true }", ["a"], JSON_DELETE);
llOwnerSay(value4);
string value5 = llJsonSetValue("[ \"a\", \"b\"}", [0], JSON_DELETE);
llOwnerSay(value5);
llJsonValueType
string llJsonValueType(string json, list specifiers)
指定したパスにある値のタイプを取得します。第一引数に対象のJSONを指定して、第二引数のListでパスを指定します。返り値は、以下の定数のどれかです。
- JSON_INVALID
- JSON_OBJECT
- JSON_ARRAY
- JSON_NUMBER
- JSON_STRING
- JSON_NULL
- JSON_TRUE
- JSON_FALSE
string json = "[ \"c\", 3, false, { \"a\" : null, \"b\" : true } ]";
string type1 = llJsonValueType(json, [0]);
if(type1 == JSON_STRING) llOwnerSay("string");
string type2 = llJsonValueType(json, [1]);
if(type2 == JSON_NUMBER) llOwnerSay("number");
string type3 = llJsonValueType(json, [3, "b"]);
if(type3 == JSON_TRUE) llOwnerSay("true");
string type4 = llJsonValueType(json, [3, "a"]);
if(type4 == JSON_NULL) llOwnerSay("null");
string type5 = llJsonValueType(json, [3]);
if(type5 == JSON_OBJECT) llOwnerSay("object");
string type6 = llJsonValueType(json, [9]);
if(type6 == JSON_INVALID) llOwnerSay("invalid");
以上で、単要素処理編はおしまいです。しかしJSONのパスをリストで表すというのが、なんか斬新でした。次回、一括変換編は万一アドベントカレンダーが完走しなかった場合に書こうとおもいます。ま、まあきっと完走するよね・・・。