第四章 Caché JSON 處理資料型別

yaoxin521123發表於2020-12-31

第四章 Caché JSON 處理資料型別

使用%GetTypeOf()返回值的資料型別

可以使用%GetTypeOf()方法獲取動態實體成員的資料型別。動態物件屬性或陣列元素可以具有下列任何一種資料型別:

  • 物件資料型別:
  1. array 動態陣列引用
  2. object 動態物件引用
  3. oref 對不是動態實體的cache物件的引用
  • 文字值:
  1. number 數字
  2. string 字串或字串文字的表示式
  • JSON 文字值:
  1. boolean JSON文字 true或 false
  2. null JSON文字 null
  • 沒有資料型別:
  1. unassigned 屬性或元素存在,但沒有賦值。

物件使用%GetTypeOf

當對物件使用此方法時,引數是屬性的名稱。例如:

/// d ##class(PHA.OP.MOB.Test).TestGetTypeObjects()
ClassMethod TestGetTypeObjects()
{
	set dynobj={"prop1":123,"prop2":[7,8,9],"prop3":{"a":1,"b":2}}
	set iter = dynobj.%GetIterator()
	while iter.%GetNext(.name) {write !,"Datatype of "_name_" is "_(dynobj.%GetTypeOf(name))}
}
DHC-APP>d ##class(PHA.OP.MOB.Test).TestGetTypeObjects()
 
Datatype of prop1 is number
Datatype of prop2 is array
Datatype of prop3 is object

對陣列使用%GetTypeOf

當對陣列使用此方法時,引數是元素的索引。下面的示例研究一個稀疏陣列,其中元素2沒有賦值。該示例使用for迴圈,因為%GetNext()將跳過未分配的元素:

/// d ##class(PHA.OP.MOB.Test).TestGetTypeArray()
ClassMethod TestGetTypeArray()
{
	set dynarray = [12,34]
	set dynarray."3" = "final"
	write dynarray.%ToJSON()
	for index = 0:1:3 {write !,"Datatype of "_index_" is "_(dynarray.%GetTypeOf(index))}
}
DHC-APP>d ##class(PHA.OP.MOB.Test).TestGetTypeArray()
[12,34,null,"final"]
Datatype of 0 is number
Datatype of 1 is number
Datatype of 2 is unassigned
Datatype of 3 is string

區分陣列或物件和oref

動態實體的資料型別將是陣列或物件。不是動態實體的Caché 物件將是資料型別oref。在下面的示例中,物件dyn的每個屬性都是這三種資料型別之一。

屬性dynobjectclass %DynamicObject,屬性dynarray%DynamicArray,屬性streamobj%Stream.GlobalCharacter:

/// d ##class(PHA.OP.MOB.Test).TestGetTypeOref()
ClassMethod TestGetTypeOref()
{
	s a="字串"
	set dyn={"dynobject":{"a":1,"b":2},"dynarray":[3,4],"streamobj":(##class(%Stream.GlobalCharacter).%New()),"a":(a)}
	set iterator=dyn.%GetIterator()
	while iterator.%GetNext(.key,.val) { write !, "Datatype of "_key_" is: "_dyn.%GetTypeOf(key) }
}
DHC-APP>d ##class(PHA.OP.MOB.Test).TestGetTypeOref()
Datatype of dynobject is: object
Datatype of dynarray is: array
Datatype of streamobj is: oref
Datatype of a is: string

注意: 在 json字串中引用Caché oject變數 可以在()中使用

%Set()%Push()重寫覆蓋預設資料型別

預設情況下,Caché 自動將%Set()%Push()值引數解釋為物件資料型別(物件、陣列或oref)或Caché 文字資料型別(字串或數字)。

不能直接將JSON字面量nulltruefalse作為值傳遞,因為引數被解釋為Caché字面量或表示式。

例如,下面的程式碼丟擲一個錯誤,因為Caché 將true解釋為一個變數名:

/// d ##class(PHA.OP.MOB.Test).TestDatatype()
ClassMethod TestDatatype()
{
   s o={}
   do o.%Set("prop3",true)
   write o.%ToJSON()
}
DHC-APP> d ##class(PHA.OP.MOB.Test).TestDatatype()
 
   do o.%Set("prop3",true)
   ^
<UNDEFINED>zTestDatatype+2^PHA.OP.MOB.Test.1 *true

Caché 對null使用“”(一個空字串),對boolean false使用0,對boolean true使用非零數字。為了處理這個問題,%Set()%Push()使用可選的第三個引數來指定值的資料型別。

第三個引數可以是JSON boolean,也可以是null。例如:

/// d ##class(PHA.OP.MOB.Test).TestDatatypeThird()
ClassMethod TestDatatypeThird()
{
	write {}.%Set("a",(2-4)).%Set("b",0).%Set("c","").%ToJSON(),!
	write {}.%Set("a",(2-4),"boolean").%Set("b",0,"boolean").%Set("c","","null").%ToJSON(),!
}
DHC-APP>d ##class(PHA.OP.MOB.Test).TestDatatypeThird()
{"a":-2,"b":0,"c":""}
{"a":true,"b":false,"c":null}

第三個引數也可以是字串或數字,如果值可以解釋為一個數字:

/// d ##class(PHA.OP.MOB.Test).TestDatatypeThirdArgument()
ClassMethod TestDatatypeThirdArgument()
{
	write [].%Push("023"_"04").%Push(5*5).%ToJSON(),!
	write [].%Push(("023"_"04"),"number").%Push((5*5),"string").%ToJSON(),!
}
DHC-APP>d ##class(PHA.OP.MOB.Test).TestDatatypeThirdArgument()
["02304",25]
[2304,"25"]

解析JSON空值和布林值

在JSON語法中,值truefalsenull與值10“”(空字串)不同,但是Caché ObjectScript沒有這種區別。當從元素或屬性檢索JSON值時,總是將它們轉換為與object script相容的值。這意味著JSON true總是返回為1,false為0,null為“”。在大多數情況下,這將是理想的結果,因為返回值可以在Caché 表示式中使用,而無需首先將其從JSON格式轉換過來。動態實體在內部保留原始的JSON或Caché 值,因此可以在必要時使用%GetTypeOf()來標識實際的資料型別。

在下面的示例中,動態陣列建構函式指定JSON真、假、空值、數字和字串文字值,以及ObjectScript動態表示式(計算結果以Caché 布林值1和0):

/// d ##class(PHA.OP.MOB.Test).TestBooleanValues()
ClassMethod TestBooleanValues()
{
	set test = [true,1,(1=1),false,0,(1=2),"",null]
	write test.%ToJSON()
}
DHC-APP>d ##class(PHA.OP.MOB.Test).TestBooleanValues()
[true,1,1,false,0,0,"",null]

正如上面所看到的,建構函式中分配的值被儲存在結果的動態陣列中,並在序列化為JSON字串時被正確顯示。

下面的示例檢索並顯示陣列值JSON值truefalsenull被轉換為與Caché 相容的值10“”:

/// d ##class(PHA.OP.MOB.Test).TestBooleanValues()
ClassMethod TestBooleanValues()
{
	set test = [true,1,(1=1),false,0,(1=2),"",null]
	write test.%ToJSON(),!
	set iter = test.%GetIterator()
	while iter.%GetNext(.key,.val){write "/"_val_"/ ",!}
}
DHC-APP>d ##class(PHA.OP.MOB.Test).TestBooleanValues()
[true,1,1,false,0,0,"",null]
/1/
/1/
/1/
/0/
/0/
/0/
//
//

本例使用%GetNext(),但是如果使用%get()%Pop()或點語法檢索值,則會得到相同的結果。

必要時,可以使用%GetTypeOf()方法來發現值的原始資料型別。例如:

/// d ##class(PHA.OP.MOB.Test).TestBooleanValues()
ClassMethod TestBooleanValues()
{
	set test = [true,1,(1=1),false,0,(1=2),"",null]
	write test.%ToJSON(),!
	set iter = test.%GetIterator()
	while iter.%GetNext(.key,.val){write "/"_val_"/ ",!}
	set iter = test.%GetIterator()
    while iter.%GetNext(.key,.val) {write !,key_": /"_test.%Get(key)_"/ = "_test.%GetTypeOf(key)}
}

DHC-APP>d ##class(PHA.OP.MOB.Test).TestBooleanValues()
[true,1,1,false,0,0,"",null]
/1/
/1/
/1/
/0/
/0/
/0/
//
//
 
0: /1/ = boolean
1: /1/ = number
2: /1/ = number
3: /0/ = boolean
4: /0/ = number
5: /0/ = number
6: // = string
7: // = null

注意:動態物件中的資料型別。 雖然本章主要討論動態陣列,但是相同的資料型別轉換也適用於動態物件值。如果將動態陣列測試定義為動態物件,則本節中的示例將完全相同:

set test = {"0":true,"1":1,"2":(1=1),"3":false,"4":0,"5":(1=2),"6":"","7":null}

除了這一行之外,示例程式碼都不需要修改。此物件中的屬性名是與原始陣列的索引號對應的數字字串,因此即使輸出也是相同的。

解決Null、空字串和未賦值

儘管可以將JSON null值賦給元素或屬性,但該值總是以“”(Caché空字串)的形式返回。如果試圖獲取未分配元素的值,也將返回空字串。可以使用%GetTypeOf()來識別每種情況下的實際資料型別。

本例將測試一個包含JSON null值和空字串的稀疏陣列。雖然陣列元素2沒有賦值,但它在JSON字串中表示為null:

/// d ##class(PHA.OP.MOB.Test).TestArrayNull()
ClassMethod TestArrayNull()
{
	set array = [null,""]
	do array.%Set(3,"last")
	write array.%ToJSON()
}
DHC-APP> d ##class(PHA.OP.MOB.Test).TestArrayNull()
[null,"",null,"last"]

在大多數情況下,將使用%GetNext()來檢索陣列值,但是本例使用for迴圈來返回未分配的值,而%GetNext()將跳過這些值。

最後一個元素的索引號是array.%Size()-1,但是迴圈計數器被故意設定為超過陣列的末尾:

/// d ##class(PHA.OP.MOB.Test).TestArrayNull()
ClassMethod TestArrayNull()
{
	set array = [null,""]
	do array.%Set(3,"last")
	write array.%ToJSON(),!
	
	for i=0:1:(array.%Size()) {write !,i_". value="""_array.%Get(i)_""" type="_array.%GetTypeOf(i)}
}
DHC-APP> d ##class(PHA.OP.MOB.Test).TestArrayNull()
[null,"",null,"last"]
 
0. value="" type=null
1. value="" type=string
2. value="" type=unassigned
3. value="last" type=string
4. value="" type=unassigned

在本例中,%Get()在四種不同的情況下返回空字串:

  • 元素0是一個JSON空值,%GetTypeOf()將其標識為資料型別null
  • 元素1是一個空字串,它被標識為資料型別字串。
  • 元素2沒有值,被標識為未分配的資料型別。
  • 雖然元素3是陣列中的最後一個元素,但是示例嘗試為不存在的元素4獲取一個資料型別,該元素也被標識為未分配的資料型別。有效的陣列索引號總是小於array.%Size()

注意:nullunassigned之間的區別是Caché 後設資料,當動態實體序列化為JSON字串時,這些後設資料不會被保留。所有未分配的元素都將序列化為null值。

相關文章