第四章 Caché JSON 处理数据类型

第四章 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值。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356

推荐阅读更多精彩内容