Skip to main content

ダイナミック・エンティティと JSON の間の変換

%ToJSON() メソッドを使用してダイナミック・エンティティをシリアル化 (JSON 文字列に変換) でき、%FromJSON() メソッドと %FromJSONFile() メソッドを使用して非シリアル化 (JSON をダイナミック・エンティティに変換) できます。

ダイナミック・エンティティから JSON へのシリアル化

次の例では、ダイナミック・オブジェクトを作成して変更してから、%ToJSON() を使用してこのダイナミック・オブジェクトをシリアル化して、結果として得られる文字列を表示します。

   set dynObject={"prop1":true}.%Set("prop2",123).%Set("prop3","foo")
   set objString = dynObject.%ToJSON()
   write objString

{"prop1":true,"prop2":123,"prop3":"foo"}

動的配列は同じ方法でシリアル化されます。

   set dynArray=[].%Push("1st value").%Push("2nd value").%Push("3rd value")
   set arrayString = dynArray.%ToJSON()
   write arrayString

["1st value","2nd value","3rd value"]

これらの両方の例ではメソッドの連鎖を使用しています (本章で前出の “メソッドの連鎖” を参照してください)。

JSON からダイナミック・オブジェクトへの非シリアル化

%FromJSON() メソッドは、JSON 文字列をダイナミック・エンティティに変換します。次の例では、動的配列を作成して、この動的配列を jstring という文字列にシリアル化します。%FromJSON() を呼び出すことによって、jstringnewArray という名前の新しいダイナミック・エンティティに非シリアル化された後、このダイナミック・エンティティが変更されて表示されます。

   set jstring=["1st value","2nd value","3rd value"].%ToJSON()
   set newArray={}.%FromJSON(jstring)
   do newArray.%Push("new value")
   write "New entity:"_newArray.%ToJSON()

New entity:["1st value","2nd value","3rd value","new value"]

この例では、返される値は動的配列ですが、%FromJSON() がダイナミック・オブジェクト・コンストラクタ ({}) から呼び出されることに注目してください。%FromJSON()%DynamicAbstractObjectOpens in a new tab のクラス・メソッドであるため、任意のダイナミック・エンティティまたはコンストラクタから呼び出すことができます。

.json ファイルに格納した JSON データがある場合は、%FromJSON() メソッドではなく、%FromJSONFile() メソッドを使用してそのデータを非シリアル化できます。

%ToJSON() と %FromJSON() を使用した複製

%FromJSON() を呼び出すたびに新しいダイナミック・エンティティが作成されるため、このメソッドを使用して、既存のエンティティを複製したり一連の同一エンティティを初期化したりできます。

次の例では、dynObj.address プロパティの値はダイナミック・オブジェクトです。このプロパティは変数 addrPointer によって参照され、このプロパティの値は、%FromJSON() を呼び出して新しいダイナミック・オブジェクト addrClone を作成することによって複製されます。

   set dynObj = {}.%FromJSON({"name":"greg", "address":{"road":"Dexter Ave."}}.%ToJSON())
   set addrPointer = dynObj.address
   set addrClone = {}.%FromJSON(dynObj.address.%ToJSON())

変数 addrPointer はプロパティ dynObj.address の単なる参照ですが、addrClone は、元の値に影響を与えることなく変更可能な %DynamicObjectOpens in a new tab の独立したインスタンスです。

   set addrPointer.road = "Wright Ave."
   set addrClone.road = "Sinister Ave."
   write !,"Property = "_dynObj.address.%ToJSON(),!,"Clone = "_addrClone.%ToJSON()

Property = {"road":"Wright Ave."}
Clone = {"road":"Sinister Ave."}

.json ファイルに格納した JSON データがある場合は、%FromJSON() メソッドではなく、%FromJSONFile() メソッドを使用してそのデータをクローン化できます。

大きいダイナミック・エンティティからストリームへのシリアル化

ダイナミック・エンティティが非常に大きい場合、%ToJSON() の出力が文字列の最大許容長を超える可能性があります (“文字列長の制限” を参照)。このセクションの例では、longStr という名前の最大長の文字列を使用しています。以下のコード例は、longStr の生成方法を示しています。

   set longStr=""
   for i=1:1:$SYSTEM.SYS.MaxLocalLength() { set longStr = longStr_"x" }
   write "Maximum string length = "_$LENGTH(longStr)

Maximum string length = 3641144

式で %ToJSON() の返り値が使用されるたびに、プログラム・スタック上にその文字列が構築されます (この文字列には文字列長の制限が適用されます)。例えば、write dyn.%ToJSON() などの読み取り/書き込み文や、set x=dyn.%ToJSON() などの代入文は、その文字列をスタック上に配置しようとします。次の例では、longStr の 2 つのコピーを動的配列に追加して、このシリアル化された文字列を変数に代入しようとしており、その結果として ObjectScript は <MAXSTRING> エラーを返しています。

   set longArray = [(longStr),(longStr)]
   set tooBig = longArray.%ToJSON()
SET tooBig = longArray.%ToJSON()
^
<MAXSTRING>

この問題の一般的な解決策は、返り値を実際に調べることなく、DO コマンド内の参照によって %ToJSON() の出力を渡すことです。出力は現在のデバイスに直接書き込まれるため、出力の長さに制限はありません。次の例では、デバイスはストリームです。

ファイル・ストリームへの書き込み

この例では、ダイナミック・オブジェクト longObject をファイルに書き込んでから、このダイナミック・オブジェクトを取得します。変数 longStr は、このセクションの冒頭で定義した値です。

   set longStr=""
   for i=1:1:$SYSTEM.SYS.MaxLocalLength() { set longStr = longStr_"x" }
   set longObject = {"a":(longStr),"b":(longStr)}
   set file=##class(%File).%New("c:\temp\longObjectFile.txt")
   do file.Open("WSN")
   do longObject.%ToJSON(file)
   do file.Close()

   set newObject = {}.%FromJSONFile(file.Name)
   write !,"Property newObject.a is ",$LENGTH(newObject.a)," characters long."

Property newObject.a is 3641144 characters long.

この解決策を使用して、他のストリームから入力を読み取ることもできます。

グローバル文字ストリームの読み取りと書き込み

この例では、2 つの大きいダイナミック・エンティティをシリアル化します (%ToJSON() はストリームごとに 1 つのエンティティしかシリアル化できないため、一時ストリームを使用しています)。標準のストリーム処理メソッドを使用して、各一時ストリームを別々の行としてストリーム bigLines に格納します。

   set tmpArray = ##class(%Stream.GlobalCharacter).%New()
   set dyn = [(longStr),(longStr)]
   do dyn.%ToJSON(tmpArray)

   set tmpObject = ##class(%Stream.GlobalCharacter).%New()
   set dyn = {"a":(longStr),"b":(longStr),"c":(longStr)}
   do dyn.%ToJSON(tmpObject)

   set bigLines = ##class(%Stream.GlobalCharacter).%New()
   do bigLines.CopyFrom(tmpArray)
   do bigLines.WriteLine()
   do bigLines.CopyFrom(tmpObject)

後で、bigLines から各ダイナミック・エンティティを非シリアル化できます。

   do bigLines.Rewind()
   while ('bigLines.AtEnd) {
      write !,{}.%FromJSON(bigLines.ReadLineIntoStream())
   }

7@%Library.DynamicArray
7@%Library.DynamicObject

FeedbackOpens in a new tab