JSON 文字列と EGL 変数の間の対応

このトピックでは、JSON (JavaScript Object Notation) 文字列に対応する EGL レコードについて説明します。 その他のトピックでは、サード・パーティー REST サービスにアクセスする場合などに 必要とされる、JSON データと変数の間の変換のために Rich UI 開発者が使用する serviceLib.convertFromJSON() 関数および serviceLib.convertToJSON() 関数について説明します。このいずれの関数で障害が発生した場合も、RuntimeException になります。

JSON と EGL レコード

次のような、JSON 文字列にアクセスする場合に使用するレコードを定義できます。
{ "EmpNo":10,"LastName":"Smith" }  
JSON 文字列の大括弧内で、各識別子と値のペア (例えば、"Empno":10) は、JSON フィールドの名前と値です。JSON 文字列に一致するレコード・パーツを作成するには、レコード・パーツの各フィールド名を、次の例に示すように、(文字および大/小文字の区別に関して) JSON 文字列の対応する各フィールド名に正確に一致させます。
Record MyRecordPart
   EmpNo INT;
   LastName STRING;
end

BLOB または CLOB 以外の任意のプリミティブ型を使用できます。 EGL レコード・フィールドについても、このフィールドが DataItem パーツに基づいていて、さらにその DataItem パーツが、サポートしているプリミティブ型のいずれかに基づいている場合であれば、有効です。

EGL プロパティー JSONName を 使用すると、EGL の予約語であったり、EGL では無効であったりするフィールド名を含む JSON 文字列を処理できます。次は、JSON 文字列の例のバリエーションです。
{ "Emp-No":10,"LastName":"Smith" }  
この場合は 、ハイフンを含む EGL レコード・フィールド名を作成できないことが問題になります。 ただし、次に示すように、プロパティー JSONName を 使用すると、レコード・パーツで JSON フィールド名を保持できます。
Record MyRecordPart
   EmpNo INT; {JSONName = "Emp-No"}
   LastName STRING;
end

(レコード・パーツに基づくレコードを宣言するときに、JSONName の値をオーバーライドすることはできません。)

多くの場合、JSON 文字列へのアクセスに使用するレコードには、複数のレコードが含まれます。 ただし、複数のレコードを使用して serviceLib.convertFromJSON() または serviceLib.convertToJSON() を呼び出す場合は、必要なすべてのレコード・パーツの最上位に位置する (最も包括的な) レコード・パーツに基づく、単一のレコードのみを参照します。例えば、次の JSON 文字列は、1970 年 1 月 1 日からの秒数を計算する getTime サービスから戻されます。
{"Result":{"aTimestamp":1191871152}}

一般的な規則では、JSON 文字列内の大括弧で囲まれている各節は、EGL レコードに等価である実行時 JSON オブジェクトの内容です。

現行の例では、2 つのレコード・パーツを定義する必要があります。serviceLib.convertFromJSON() または serviceLib.convertToJSON() で使用するレコードは、次のパーツに基づいています。このパーツには、Result と呼ばれるフィールドがあります。
Record MyTopPart
   Result MyTimestampPart;
end
この JSON 文字列の構造を前提として、次のレコード・パーツは aTimestamp という名前のフィールドを持ちます。
Record MyTimestampPart
   aTimestamp BIGINT;
end

示されているように、各 JSON 識別子 (コロンの前に位置します) は、レコード内にフィールドが存在することを必要とします。JSON フィールド名は EGL の予約語語 (例えば、「TimeStamp」) で、レコードではなく辞書を使用して serviceLib.convertFromJSON() または serviceLib.convertToJSON() にアクセスする必要があります。このバリエーションについては、この後このトピックで示します。

次は別の例で、JSON についての詳細な説明が掲載されている Web サイト http://json.org/ から引用しています (ただし、理解しやすくするために改編しています)。
{"Menu": 
  { "id": "file", "value": "File", "popup": 
     {"Menuitem": 
       [
         {"value": "New", "onClick": "CreateNewDoc()"},
         {"value": "Open", "onClick": "OpenDoc()"},
         {"value": "Close", "onClick": "CloseDoc()"}
       ]   
     }
  }
}

(本ヘルプの作成時点で、上記例およびその他の例は、http://json.org/example.html で公開されています)。

最上の (最も包括的な) レコード・パーツには、Menu という名前の次のフィールドが含まれます。
Record MyTopPart
   Menu MyMenuPart;
end
その他のレコード・パーツを作成するために、JSON 文字列内の大括弧で囲まれた各文節を検討します。次のレコード・パーツ (MyMenuPart) には、idvalue、および popup という名前のフィールドが含まれます。
Record MyMenuPart
   id STRING; 
   value STRING;
   popup MyPopupPart;
end
次のレコード・パーツには、MenuItem という名前の配列が含まれます。
Record MyPopupPart
   MenuItem MyElementPart[];
end
最後のレコード・パーツには、value および onClick という名前のフィールドが含まれます。
Record MyElementPart
   value STRING; 
   onClick STRING;
end

JSON 文字列にアクセスするときのレコードの使用法をさらに検討するには、Rich UI のサンプル geocode.records を参照してください。

JSON と EGL 辞書

EGL 辞書には 1 セットのエントリーが含まれており、それぞれのエントリーが、次の変数宣言のようにデータ型のキーと値の両方で構成されています。
myRef Dictionary 
{ 
   ID = 5,
   lastName = "Twain",
   firstName = "Mark"
};

EGL ヘルプ・システムの『Dictionary パーツ』および関連するトピックで説明されているように、辞書と対話します。

次の JSON 文字列は、1970 年 1 月 1 日からの秒数を計算する getTime サービスから戻されます。
{"Result":{"aTimestamp":1191871152}}
JSON 文字列を (最左端から最右端の大括弧に向かって) myTime という名前の辞書に変換することもできます。これは、次のように、詳細なしで宣言されます。
myTime Dictionary;

一般的な規則では、JSON 文字列内の大括弧で囲まれている文節は EGL 辞書に等価です。本ヘルプの JSON 文字列の例に関しては、関数 serviceLib.convertFromJSON() により、最初のコロン (:) の左側の記号は辞書エントリーのキーとして取り扱われます。キーは「Result」で、大/小文字が区別がされます。ここで、(すべてのケースで同じですが)、コロンの右の内容は、名前がコロンの左にあるキーに関連付けられている値です。

内側に埋め込まれている大括弧は、「Result」の値が無名辞書であることを示しています。前述のように、大括弧内のコロンにより、キー (aTimestamp) と値 (1191871152) が区別されます。つまり、関数 serviceLib.convertFromJSON() の出力を次のように考えることができます。
myTime Dictionary 
{ 
   Result = new Dictionary{ aTimestamp = 1191871152 }
};   
aTimestamp の内容には、点で区切られた次の構文を使用してアクセスできます。
numberOfSeconds BIGINT = myTime.Result.aTimestamp;
点で区切られた構文が無効の場合があります。例えば、Yahoo の getTime サービスでは、EGL の予約語 Timestamp を含む、次の内容が返されました。
{"Result":{"Timestamp":1191871152}}
キーが EGL 予約語である値にアクセスするには、大括弧構文を使用する必要があります。次の EGL コードは、Yahoo の getTime サービスから戻されたデータに対して有効です。
numberOfSeconds BIGINT = myTime.Result["Timestamp"];
次も、http://json.org/ から引用した Menu の例です。
{"Menu": 
  { "id": "file", "value": "File", "popup": 
     {"Menuitem": 
       [
         {"value": "New", "onClick": "CreateNewDoc()"},
         {"value": "Open", "onClick": "OpenDoc()"},
         {"value": "Close", "onClick": "CloseDoc()"}
       ]   
     }
  }
}

この例では、辞書は、キーが Menu という名前の単一のエントリーを持ちます。このキーに関連付けられている値は、文字列「id」とそれに続くすべての文字列が内側に埋め込まれている大括弧で示されるように、無名辞書です。無名辞書には、キーの ID、およびポップアップが、キーの値とともに含まれます。ポップアップと呼ばれるキーにより若干の複雑さが導入されますが、そのような問題についても処理できます。これらの関連は、例の JSON 文字列で確認できます。

ここで、「関数 serviceLib.convertFromJSON() により直前の JSON 文字列が myMenu と呼ばれる辞書にコピーされているものとして、文字列「OpenDoc()」にアクセスするために必要なステートメントは何か」について検討します。

答えは次のとおりです。
myString STRING = myMenu.Menu.popup.MenuItem[2].onClick;
次の EGL 辞書は、現行の例を反映しています。
myMenu Dictionary
{  Menu = new Dictionary
   { id = "file",
     value = "File",
     popup = new Dictionary 
     { MenuItem = new Dictionary[]
       { new dictionary {value = "New", onClick = "CreateNewDoc()" },
         new dictionary {value = "Open", onClick = "OpenDoc()" },
         new dictionary {value = "Close", onClick = "CloseDoc()"}
       } 
     } 
   }
};     
関数 serviceLib.convertToJSON() を使用するには、前述の例で示されているように構造化された辞書を作成することから開始します。以下の 2 つの規則が適用されます。
  • 辞書の階層内の各辞書は、JSON 文字列の大括弧で囲まれた文節と等価です。
  • 各キーにはプリミティブ値、辞書、レコード、または辞書あるいはレコードの配列が割り当てられます。

JSON 文字列にアクセスするときの辞書レコードの使用法をさらに検討するには、Rich UI のサンプル geocode.dictionaries を参照してください。

JSON、およびレコードと辞書の両方

以下のケースではレコードと辞書を混合できます。
  • レコードを使用して serviceLib.convertFromJSON() を呼び出す準備をしているとき。
  • レコードまたは辞書を使用して serviceLib.convertToJSON() を呼び出す準備をしているとき。
次の JSON 文字列にアクセスするために、レコードに辞書を含める場合があります。
{"Result":{"Timestamp":1191871152}}
次のパーツを定義できます。
Record ResultRecordPart
   Result Dictionary;
end
コードで、次のように、タイム・スタンプ値にアクセスできます。
   myResult ResultRecordPart;
   milliseconds BIGINT;
		serviceLib.convertFromJSON(resp.body, myResult);
		milliseconds = myResult.Result["Timestamp"] as BIGINT;
一般的な規則では、着信 JSON 文節を辞書に関連付けると、辞書構文を使用するだけで文節内のデータにアクセスできます。複雑な例は次のとおりです。
{"Menu": 
  { "id": "file", "value": "File", "popup": 
     {"Menuitem": 
       [
         {"value": "New", "onClick": "CreateNewDoc()"},
         {"value": "Open", "onClick": "OpenDoc()"},
         {"value": "Close", "onClick": "CloseDoc()"}
       ]   
     }
  }
}
内容にアクセスする準備をするには、以下のパーツを定義します。
Record MyTopPart
   Menu MyMenuPart;
end

Record MyMenuPart
   id STRING; 
   value STRING;
   popup Dictionary; 
end
以下の EGL 辞書は、popup という名前の構造を反映しています。
   popup Dictionary 
   { MenuItem = new Dictionary[]
      { new Dictionary {value = "New", onClick = "CreateNewDoc()" },
        new Dictionary {value = "Open", onClick = "OpenDoc()" },
        new Dictionary {value = "Close", onClick = "CloseDoc()"}
      } 
   } 

(上記辞書は、説明のために示しています。Dictionary の副構造は serviceLib.convertToJSON() の呼び出し時には役立つ可能性がありますが、serviceLib.convertFromJSON() の呼び出し時には使用しません。)

次のコードは、文字列「OpenDoc()」にアクセスします。
   myTop MyTopPart;
   itemString STRING;
   serviceLib.convertFromJSON(resp.body, myTop);
   itemString = myTop.Menu.popup.MenuItem[2].onClick;

フィードバック