如何解析来自 HTTP JSON 响应负载的值
How to parse value from HTTP JSON response payload
我对 Apama 比较陌生。我正在使用 v10.3.1。我正在按照以下代码片段在监视器中执行 REST 请求:
当前处理响应的操作如下所示:
action handleResponse(Response response){
if response.isSuccess(){
print "###The response payload is :" + response.payload.toString();
}
else {
print "###Request failed. Response status is: " + response.statusCode.toString() + " | " + response.statusMessage;
}
}
我正在寻找在 JSON 响应负载中提取以下 属性 值的最佳方法:
assetparents.references[0].managedObject.name (here “SOME”).
我尝试了不同的方法,但总是 运行 出错。
打印语句为响应负载提供以下输出:
###The response payload is :com.apama.util.AnyExtractor(any(string,"
{"owner":"some@one.com","additionParents":{
"self":"https://somebaseurl/inventory/managedObjects/5706999/additionParents","references":[]
},
"childDevices":{
"self":"https://somebaseurl/inventory/managedObjects/5706999/childDevices","references":[]
},
"childAssets":{
"self":"https://somebaseurl/inventory/managedObjects/5706999/childAssets","references":[]
},
"creationTime":"2019-05-09T11:36:10.197Z",
"lastUpdated":"2019-05-10T05:28:07.893Z",
"childAdditions":{
"self":"https://somebaseurl/inventory/managedObjects/5706999/childAdditions",
"references":[{
"managedObject":{"name":"Escalate alarmtest",
"self":"https://somebaseurl/inventory/managedObjects/5706698",
"id":"5706698"},
"self":"https://somebaseurl/inventory/managedObjects/5706999/childAdditions/5706698"
}
]},
"name":"SOME Test Device",
"deviceParents":{
"self":"https://somebaseurl/inventory/managedObjects/5706999/deviceParents",
"references":[]
},
"assetParents":{
"self":"https://somebaseurl/inventory/managedObjects/5706999/assetParents",
"references":[{
"managedObject":{
"additionParents":{
"self":"https://somebaseurl/inventory/managedObjects/5706682/additionParents",
"references":[]
},
"childDevices":{
"self":"https://somebaseurl/inventory/managedObjects/5706682/childDevices",
"references":[]
},
"childAssets":{
"self":"https://somebaseurl/inventory/managedObjects/5706682/childAssets",
"references":[]
},
"childAdditions":{
"self":"https://somebaseurl/inventory/managedObjects/5706682/childAdditions",
"references":[]
},
"name":"SOME",
"deviceParents":{
"self":"https://somebaseurl/inventory/managedObjects/5706682/deviceParents",
"references":[]
},
"assetParents":{
"self":"https://somebaseurl/inventory/managedObjects/5706682/assetParents",
"references":[]
},
"self":"https://somebaseurl/inventory/managedObjects/5706682",
"id":"5706682"
},
"self":"https://somebaseurl/inventory/managedObjects/5706999/assetParents/5706682"
}]
},
"self":"https://somebaseurl/inventory/managedObjects/5706999",
"id":"5706999",
"c8y_ActiveAlarmsStatus":{
"minor":0,
"critical":1
},
"c8y_IsDevice":{},
"ax_Customer":"SOME CUSTOMER",
"c8y_SupportedMeasurements":["c8y_Temperature"]}"))
除了解析单个 属性 之外,将整个对象映射到 Apama 事件的推荐方法是什么?
如果您能提供代码片段,我们将不胜感激。
非常感谢
马蒂亚斯
回答你的第一个问题。
打印语句的输出非常有帮助。它表明响应有效负载是原始 JSON 字符串而不是经过解析的 JSON object。这意味着 JOSN 编解码器跳过了对 JSON srting 的解码。如果 contentType
header 不完全是 application/json
,则在使用 "JSON with generic request/response event definitions" plug-in 时会发生这种情况。使用 Cumulocity 进行的测试表明,header 的值并不总是 application/json
,而是可能类似于 application/vnd.com.nsn.cumulocity.managedobject+json
或 application/vnd.com.nsn.cumulocity.measurementcollection+json
,而当前的 JSON 编解码器不能处理。
在 JSON 编解码器中没有任何更改的情况下,您可以通过两种方式处理它。
1) 禁用 JSON 编解码器
的消息过滤
"JSON with generic request/response event definitions" plug-in 使用的 JSON 编解码器配置为跳过未将 contentType
header 设置为 [=12= 的解码消息].这可以通过编辑 Designer 项目中 "Connectivity and Adapters/HTTP Client/HTTPClient" 节点下的 HTTPClient.yaml
文件来禁用。将 filterOnContentType
属性 设置为 false
。这将导致所有响应都被处理为 JSON;如果负载不是 JSON,解析将失败并且消息将被丢弃。因此,仅当您确定所有响应都是 JSON.
时才启用此功能
2) 解析 EPL
中的 JSON 个字符串
其他选项可能是在 EPL 本身中将字符串解析为 JSON,然后将 JSON object 包装到 AnyExtractor
中以提取所需的值。你可以使用类似下面的东西来做到这一点。
using com.apama.json.JSONPlugin;
using com.apama.util.AnyExtractor;
...
action handleResponse(Response res) {
if res.isSuccess() {
log "Response is: " + res.toString();
// Check if payload is string. A string payload could suggest raw JSON string
switch (res.payload.data as payload) {
case string: {
// Parse the JSON string manually
AnyExtractor extractor := AnyExtractor(JSONPlugin.fromJSON(payload));
string name := extractor.getString("assetparents.references[0].managedObject.name");
}
default: {
// probably already parsed to JSON - use AnyExtractor to work on it
}
}
} else {
log "Failed: " + res.statusMessage at ERROR;
}
}
回答你的第二个问题,即"what is the recommended way to map the entire object to an Apama event?":
我已经定义了几个事件,这些事件将映射到您提供的 JSON:
event Reference {
string self;
any managedObject;
}
event Object {
string self;
sequence<Reference> references;
}
event ActiveAlarmsStatus {
integer minor;
integer critical;
}
event IsDevice {}
event ManagedObject {
string owner;
string self;
string id;
string name;
string creationTime;
string lastUpdated;
Object additionParents;
Object childDevices;
Object childAssets;
Object childAdditions;
Object deviceParents;
Object assetParents;
ActiveAlarmsStatus c8y_ActiveAlarmsStatus;
IsDevice c8y_IsDevice;
string ax_Customer;
sequence<string> c8y_SupportedMeasurements;
}
因为 ManagedObject 包含一个 Object,而该对象又包含一个 Reference,而 Reference 本身又包含一个 ManagedObject,由于递归类型,EPL 无法编译。因此,在 Reference 中我们使用 any 类型来屏蔽 ManagedObject。这允许 EPL 编译。
但是,因为 any 隐藏了类型,我们不知道将它转换成什么类型,所以我们有一个包含字典的 any。不过这很好,因为我们可以使用一些辅助函数来提取我们想要的信息:
action GetSequenceReference(sequence<any> s) returns sequence<Reference> {
sequence<Reference> ret := new sequence<Reference>;
any r := new any;
for r in s {
ret.append(<Reference>r);
}
return ret;
}
action GetSequenceString(sequence<any> s) returns sequence<string> {
sequence<string> ret := new sequence<string>;
any r := new any;
for r in s {
ret.append(<string>r);
}
return ret;
}
action GetObject(any a) returns Object {
log "Getting object from: " + a.toString() at INFO;
dictionary<any,any> dict := <dictionary<any,any> >a;
Object ret := new Object;
ret.self := <string>dict.getDefault( "self", "" );
ret.references := GetSequenceReference( <sequence<any> >dict.getDefault( "references", new sequence<any> ) );
return ret;
}
action GetActiveAlarmsStatus(any a) returns ActiveAlarmsStatus {
log "Getting active alarms status from: " + a.toString() at INFO;
dictionary<any,any> dict := <dictionary<any,any> >a;
ActiveAlarmsStatus ret := new ActiveAlarmsStatus;
ret.minor := <integer>dict.getDefault( "minor", 0 );
ret.critical := <integer>dict.getDefault( "critical", 0 );
return ret;
}
action GetIsDevice(any a) returns IsDevice {
log "Getting is device from: " + a.toString() at INFO;
dictionary<any,any> dict := <dictionary<any,any> >a;
IsDevice ret := new IsDevice;
return ret;
}
action GetManagedObject(any a) returns ManagedObject {
log "Getting managed object from: " + a.toString() at INFO;
dictionary<any,any> dict := <dictionary<any,any> >a;
ManagedObject ret := new ManagedObject;
ret.owner := <string>dict.getDefault( "owner", "" );
ret.self := <string>dict.getDefault( "self", "" );
ret.id := <string>dict.getDefault( "id", "" );
ret.name := <string>dict.getDefault( "name", "" );
ret.creationTime := <string>dict.getDefault( "creationTime", "" );
ret.lastUpdated := <string>dict.getDefault( "lastUpdated", "" );
ret.additionParents := GetObject( dict.getDefault( "additionParents", new dictionary<any,any> ) );
ret.childDevices := GetObject( dict.getDefault( "childDevices", new dictionary<any,any> ) );
ret.childAssets := GetObject( dict.getDefault( "childAssets", new dictionary<any,any> ) );
ret.childAdditions := GetObject( dict.getDefault( "childAdditions", new dictionary<any,any> ) );
ret.deviceParents := GetObject( dict.getDefault( "deviceParents", new dictionary<any,any> ) );
ret.assetParents := GetObject( dict.getDefault( "assetParents", new dictionary<any,any> ) );
ret.c8y_ActiveAlarmsStatus := GetActiveAlarmsStatus( dict.getDefault( "c8y_ActiveAlarmsStatus", new dictionary<any,any> ) );
ret.c8y_IsDevice := GetIsDevice( dict.getDefault( "c8y_IsDevice", new dictionary<any,any> ) );
ret.ax_Customer := <string>dict.getDefault( "ax_Customer", "" );
ret.c8y_SupportedMeasurements := GetSequenceString( <sequence<any> >dict.getDefault( "c8y_SupportedMeasurements", new sequence<any> ) );
return ret;
}
使用这些辅助函数,我们可以从原始事件中提取信息:
action handleResponse(Response response){
if response.isSuccess(){
ManagedObject mo := GetManagedObject( response.payload.toDictionary() );
log "###The response payload is :" + mo.toString() at INFO;
}
else {
log "###Request failed. Response status is: " + response.statusCode.toString() + " | " + response.statusMessage at INFO;
}
}
给你!一个完全映射的事件。
我对 Apama 比较陌生。我正在使用 v10.3.1。我正在按照以下代码片段在监视器中执行 REST 请求:
当前处理响应的操作如下所示:
action handleResponse(Response response){
if response.isSuccess(){
print "###The response payload is :" + response.payload.toString();
}
else {
print "###Request failed. Response status is: " + response.statusCode.toString() + " | " + response.statusMessage;
}
}
我正在寻找在 JSON 响应负载中提取以下 属性 值的最佳方法:
assetparents.references[0].managedObject.name (here “SOME”).
我尝试了不同的方法,但总是 运行 出错。
打印语句为响应负载提供以下输出:
###The response payload is :com.apama.util.AnyExtractor(any(string,"
{"owner":"some@one.com","additionParents":{
"self":"https://somebaseurl/inventory/managedObjects/5706999/additionParents","references":[]
},
"childDevices":{
"self":"https://somebaseurl/inventory/managedObjects/5706999/childDevices","references":[]
},
"childAssets":{
"self":"https://somebaseurl/inventory/managedObjects/5706999/childAssets","references":[]
},
"creationTime":"2019-05-09T11:36:10.197Z",
"lastUpdated":"2019-05-10T05:28:07.893Z",
"childAdditions":{
"self":"https://somebaseurl/inventory/managedObjects/5706999/childAdditions",
"references":[{
"managedObject":{"name":"Escalate alarmtest",
"self":"https://somebaseurl/inventory/managedObjects/5706698",
"id":"5706698"},
"self":"https://somebaseurl/inventory/managedObjects/5706999/childAdditions/5706698"
}
]},
"name":"SOME Test Device",
"deviceParents":{
"self":"https://somebaseurl/inventory/managedObjects/5706999/deviceParents",
"references":[]
},
"assetParents":{
"self":"https://somebaseurl/inventory/managedObjects/5706999/assetParents",
"references":[{
"managedObject":{
"additionParents":{
"self":"https://somebaseurl/inventory/managedObjects/5706682/additionParents",
"references":[]
},
"childDevices":{
"self":"https://somebaseurl/inventory/managedObjects/5706682/childDevices",
"references":[]
},
"childAssets":{
"self":"https://somebaseurl/inventory/managedObjects/5706682/childAssets",
"references":[]
},
"childAdditions":{
"self":"https://somebaseurl/inventory/managedObjects/5706682/childAdditions",
"references":[]
},
"name":"SOME",
"deviceParents":{
"self":"https://somebaseurl/inventory/managedObjects/5706682/deviceParents",
"references":[]
},
"assetParents":{
"self":"https://somebaseurl/inventory/managedObjects/5706682/assetParents",
"references":[]
},
"self":"https://somebaseurl/inventory/managedObjects/5706682",
"id":"5706682"
},
"self":"https://somebaseurl/inventory/managedObjects/5706999/assetParents/5706682"
}]
},
"self":"https://somebaseurl/inventory/managedObjects/5706999",
"id":"5706999",
"c8y_ActiveAlarmsStatus":{
"minor":0,
"critical":1
},
"c8y_IsDevice":{},
"ax_Customer":"SOME CUSTOMER",
"c8y_SupportedMeasurements":["c8y_Temperature"]}"))
除了解析单个 属性 之外,将整个对象映射到 Apama 事件的推荐方法是什么?
如果您能提供代码片段,我们将不胜感激。
非常感谢 马蒂亚斯
回答你的第一个问题。
打印语句的输出非常有帮助。它表明响应有效负载是原始 JSON 字符串而不是经过解析的 JSON object。这意味着 JOSN 编解码器跳过了对 JSON srting 的解码。如果 contentType
header 不完全是 application/json
,则在使用 "JSON with generic request/response event definitions" plug-in 时会发生这种情况。使用 Cumulocity 进行的测试表明,header 的值并不总是 application/json
,而是可能类似于 application/vnd.com.nsn.cumulocity.managedobject+json
或 application/vnd.com.nsn.cumulocity.measurementcollection+json
,而当前的 JSON 编解码器不能处理。
在 JSON 编解码器中没有任何更改的情况下,您可以通过两种方式处理它。
1) 禁用 JSON 编解码器
的消息过滤"JSON with generic request/response event definitions" plug-in 使用的 JSON 编解码器配置为跳过未将 contentType
header 设置为 [=12= 的解码消息].这可以通过编辑 Designer 项目中 "Connectivity and Adapters/HTTP Client/HTTPClient" 节点下的 HTTPClient.yaml
文件来禁用。将 filterOnContentType
属性 设置为 false
。这将导致所有响应都被处理为 JSON;如果负载不是 JSON,解析将失败并且消息将被丢弃。因此,仅当您确定所有响应都是 JSON.
2) 解析 EPL
中的 JSON 个字符串其他选项可能是在 EPL 本身中将字符串解析为 JSON,然后将 JSON object 包装到 AnyExtractor
中以提取所需的值。你可以使用类似下面的东西来做到这一点。
using com.apama.json.JSONPlugin;
using com.apama.util.AnyExtractor;
...
action handleResponse(Response res) {
if res.isSuccess() {
log "Response is: " + res.toString();
// Check if payload is string. A string payload could suggest raw JSON string
switch (res.payload.data as payload) {
case string: {
// Parse the JSON string manually
AnyExtractor extractor := AnyExtractor(JSONPlugin.fromJSON(payload));
string name := extractor.getString("assetparents.references[0].managedObject.name");
}
default: {
// probably already parsed to JSON - use AnyExtractor to work on it
}
}
} else {
log "Failed: " + res.statusMessage at ERROR;
}
}
回答你的第二个问题,即"what is the recommended way to map the entire object to an Apama event?":
我已经定义了几个事件,这些事件将映射到您提供的 JSON:
event Reference {
string self;
any managedObject;
}
event Object {
string self;
sequence<Reference> references;
}
event ActiveAlarmsStatus {
integer minor;
integer critical;
}
event IsDevice {}
event ManagedObject {
string owner;
string self;
string id;
string name;
string creationTime;
string lastUpdated;
Object additionParents;
Object childDevices;
Object childAssets;
Object childAdditions;
Object deviceParents;
Object assetParents;
ActiveAlarmsStatus c8y_ActiveAlarmsStatus;
IsDevice c8y_IsDevice;
string ax_Customer;
sequence<string> c8y_SupportedMeasurements;
}
因为 ManagedObject 包含一个 Object,而该对象又包含一个 Reference,而 Reference 本身又包含一个 ManagedObject,由于递归类型,EPL 无法编译。因此,在 Reference 中我们使用 any 类型来屏蔽 ManagedObject。这允许 EPL 编译。
但是,因为 any 隐藏了类型,我们不知道将它转换成什么类型,所以我们有一个包含字典的 any。不过这很好,因为我们可以使用一些辅助函数来提取我们想要的信息:
action GetSequenceReference(sequence<any> s) returns sequence<Reference> {
sequence<Reference> ret := new sequence<Reference>;
any r := new any;
for r in s {
ret.append(<Reference>r);
}
return ret;
}
action GetSequenceString(sequence<any> s) returns sequence<string> {
sequence<string> ret := new sequence<string>;
any r := new any;
for r in s {
ret.append(<string>r);
}
return ret;
}
action GetObject(any a) returns Object {
log "Getting object from: " + a.toString() at INFO;
dictionary<any,any> dict := <dictionary<any,any> >a;
Object ret := new Object;
ret.self := <string>dict.getDefault( "self", "" );
ret.references := GetSequenceReference( <sequence<any> >dict.getDefault( "references", new sequence<any> ) );
return ret;
}
action GetActiveAlarmsStatus(any a) returns ActiveAlarmsStatus {
log "Getting active alarms status from: " + a.toString() at INFO;
dictionary<any,any> dict := <dictionary<any,any> >a;
ActiveAlarmsStatus ret := new ActiveAlarmsStatus;
ret.minor := <integer>dict.getDefault( "minor", 0 );
ret.critical := <integer>dict.getDefault( "critical", 0 );
return ret;
}
action GetIsDevice(any a) returns IsDevice {
log "Getting is device from: " + a.toString() at INFO;
dictionary<any,any> dict := <dictionary<any,any> >a;
IsDevice ret := new IsDevice;
return ret;
}
action GetManagedObject(any a) returns ManagedObject {
log "Getting managed object from: " + a.toString() at INFO;
dictionary<any,any> dict := <dictionary<any,any> >a;
ManagedObject ret := new ManagedObject;
ret.owner := <string>dict.getDefault( "owner", "" );
ret.self := <string>dict.getDefault( "self", "" );
ret.id := <string>dict.getDefault( "id", "" );
ret.name := <string>dict.getDefault( "name", "" );
ret.creationTime := <string>dict.getDefault( "creationTime", "" );
ret.lastUpdated := <string>dict.getDefault( "lastUpdated", "" );
ret.additionParents := GetObject( dict.getDefault( "additionParents", new dictionary<any,any> ) );
ret.childDevices := GetObject( dict.getDefault( "childDevices", new dictionary<any,any> ) );
ret.childAssets := GetObject( dict.getDefault( "childAssets", new dictionary<any,any> ) );
ret.childAdditions := GetObject( dict.getDefault( "childAdditions", new dictionary<any,any> ) );
ret.deviceParents := GetObject( dict.getDefault( "deviceParents", new dictionary<any,any> ) );
ret.assetParents := GetObject( dict.getDefault( "assetParents", new dictionary<any,any> ) );
ret.c8y_ActiveAlarmsStatus := GetActiveAlarmsStatus( dict.getDefault( "c8y_ActiveAlarmsStatus", new dictionary<any,any> ) );
ret.c8y_IsDevice := GetIsDevice( dict.getDefault( "c8y_IsDevice", new dictionary<any,any> ) );
ret.ax_Customer := <string>dict.getDefault( "ax_Customer", "" );
ret.c8y_SupportedMeasurements := GetSequenceString( <sequence<any> >dict.getDefault( "c8y_SupportedMeasurements", new sequence<any> ) );
return ret;
}
使用这些辅助函数,我们可以从原始事件中提取信息:
action handleResponse(Response response){
if response.isSuccess(){
ManagedObject mo := GetManagedObject( response.payload.toDictionary() );
log "###The response payload is :" + mo.toString() at INFO;
}
else {
log "###Request failed. Response status is: " + response.statusCode.toString() + " | " + response.statusMessage at INFO;
}
}
给你!一个完全映射的事件。