Json.NET (Newtonsoft.Json) - Two 'properties' with same name? - json

I'm coding in C# for the .NET Framework 3.5.
I am trying to parse some Json to a JObject.
The Json is as follows:
{
"TBox": {
"Name": "SmallBox",
"Length": 1,
"Width": 1,
"Height": 2 },
"TBox": {
"Name": "MedBox",
"Length": 5,
"Width": 10,
"Height": 10 },
"TBox": {
"Name": "LargeBox",
"Length": 20,
"Width": 20,
"Height": 10 }
}
When I try to parse this Json to a JObject, the JObject only knows about LargeBox. The information for SmallBox and MedBox is lost. Obviously this is because it is interpreting "TBox" as a property, and that property is being overwritten.
I am receiving this Json from a service that's coded in Delphi. I'm trying to create a C# proxy for that service. On the Delphi-side of things, the "TBox" is understood as the type of the object being returned. The inner properties ("Name", "Length", "Width", "Height") are then understood as regular properties.
I can serialize and deserialize a custom 'TBox' object that has Name, Length, Width, and Height properties. That's fine.
What I want to do is step through all the TBox sections in such a way as to extract the following three Json strings.
First:
{
"Name": "SmallBox",
"Length": 1,
"Width": 1,
"Height": 2 }
Second:
{
"Name": "MedBox"
"Length": 5,
"Width": 10,
"Height": 10 }
Third:
{
"Name": "LargeBox"
"Length": 20,
"Width": 20,
"Height": 10 }
Once I have these strings, I can serialize and deserialize to my heart's content.
I'm finding Newtonsoft.Json to be very good. I really don't want to go messing about with other frameworks if I can avoid it.
Any help would be greatly appreciated.
I have very limited input as to changes that can be made to the server.

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
JsonTextReader jsonReader = new JsonTextReader(reader);
jsonReader.Read();
while(jsonReader.Read())
{
if(jsonReader.TokenType == JsonToken.StartObject)
{
JObject tbox = JObject.Load(jsonReader);
}
}
However, note that the RFC says, "The names within an object SHOULD be unique" so if you can, recommend the format be changed.
EDIT: Here's an alternate design that doesn't have duplicate keys:
[
{
"TBox": {
"Width": 1,
"Length": 1,
"Name": "SmallBox",
"Height": 2
}
},
{
"TBox": {
"Width": 10,
"Length": 5,
"Name": "MedBox",
"Height": 10
}
},
{
"TBox": {
"Width": 20,
"Length": 20,
"Name": "LargeBox",
"Height": 10
}
}
]

If I'm not mistaken, the correct answer to this is that your input is not actually JSON. So no, getting a JSON parser to parse it probably isn't going to work.
Maybe you don't have any control over the source of the input, so I'd use a Regex or something to pre-filter the string. Turn it into something like:
{"TBoxes":
[
{
"Name": "SmallBox",
"Length": 1,
"Width": 1,
"Height": 2
},
{
"Name": "MedBox",
"Length": 5,
"Width": 10,
"Height": 10
},
{
"Name": "LargeBox",
"Length": 20,
"Width": 20,
"Height": 10
}
]
}
And treat it like the array that it is.

Related

Filter to retrieve specific value in nested object using Vue

I have a nested json object:
{
"51": {
"wheels": 10,
"id": 1,
"name": "truck"
},
"55": {
"wheels": 4,
"id": 33,
"name": "Car"
},
"88": {
"wheels": 2,
"id": 90,
"name": "Bike"
}
}
I would like to filter by ID but only return the wheels so ie.
Filter ID = 33 which would return 4.
I have tried using the .filter function but I get an error: filter is not a function which I assume is because this is not an array. I have tried to replicate using answer here:
How to filter deeply nested json by multiple attributes with vue/javascript
Without success because the json has a key (51, 55, 88) so I am stumped.
Thanks for the help in advance.
You can use Object.values to convert the object into an array and then use find method on it to retrieve the specific object. Something like:
Object.values(obj).find(val => val.id === 33)?.wheels
let obj = {
"51": {
"wheels": 10,
"id": 1,
"name": "truck"
},
"55": {
"wheels": 4,
"id": 33,
"name": "Car"
},
"88": {
"wheels": 2,
"id": 90,
"name": "Bike"
}
}
console.log(Object.values(obj).find(val => val.id === 33)?.wheels)

How to retrieve nested JSON values

I have the fallowing JSON object and I want to take the value of Microsoft.VSTS.Scheduling.RemainingWork
[
{
"id": 13,
"rev": 12,
"fields": {
"System.Id": 13,
"Microsoft.VSTS.Scheduling.RemainingWork": 32,
"Microsoft.VSTS.Scheduling.CompletedWork": 20
},
"url": "https://dev.azure.com/.../_apis/wit/workItems/13"
}
]
I am able retrieve data until some point:
console.log("object of json : ",result);
console.log("result[0] : ", result[0])
console.log("result[0].fields : ", result[0].fields)
The console output is,
But I this is not working result[0].fields.Microsoft.VSTS.Scheduling.RemainingWork
You can access data like an associative array :
result[0].fields['Microsoft.VSTS.Scheduling.RemainingWork']
You need to use
result[0].fields["Microsoft.VSTS.Scheduling.RemainingWork"]
Basically when you use
result[0].fields.Microsoft.VSTS.Scheduling.RemainingWork
each time you use a ".", you are trying to get the value from a nested object, like this -
[
{
"id": 13,
"rev": 12,
"fields": {
"System.Id": 13,
"Microsoft": {
"VSTS": {
"Scheduling": {
"RemainingWork": 32
}
}
},
"Microsoft.VSTS.Scheduling.CompletedWork": 20
},
"url": "https://dev.azure.com/.../_apis/wit/workItems/13"
}
]
which is not correct since that is not the way your data is structured.

Azure ADF - Array elements can only be selected using an integer index

Hi I am trying to select Status from Json Array in azure data factory
{
"dataRead": 2997,
"dataWritten": 2714,
"filesWritten": 1,
"sourcePeakConnections": 1,
"sinkPeakConnections": 1,
"rowsRead": 11,
"rowsCopied": 11,
"copyDuration": 3,
"throughput": 0.976,
"errors": [],
"effectiveIntegrationRuntime": "DefaultIntegrationRuntime (East US)",
"usedDataIntegrationUnits": 4,
"billingReference": {
"activityType": "DataMovement",
"billableDuration": [
{
"meterType": "AzureIR",
"duration": 0.06666666666666667,
"unit": "DIUHours"
}
]
},
"usedParallelCopies": 1,
"executionDetails": [
{
"source": {
"type": "AzureSqlDatabase",
"region": "East US"
},
"sink": {
"type": "AzureBlobStorage",
"region": "East US"
},
"status": "Succeeded",
"start": "2020-03-19T06:24:39.0666585Z",
"duration": 3,
"usedDataIntegrationUnits": 4,
"usedParallelCopies": 1,
I have tried selecting #activity('Copy data From CCP TO Blob').output.executionDetails.status.It throws an error:
'Array elements can only be selected using an integer index'.
Any way to resolve it?
executionDetails is an array, you have to set index to refer elements in it.
Please try:
#activity('Copy data From CCP TO Blob').output.executionDetails[0].status
Thank you for the reply
Yes, we have to use slicing and indexing the lists and Dictionaries
I have tried Dispensing_Unit_Master_Dim
#activity('Copy data From CCP TO Blob').output.executionDetails[0]['status'] and it works
0 and status there is no Dot

Jsonpath - Accessing array item using expression

I am using AWS Step Functions which utilizes JSONPath for providing JSON paths. I have the following input :
{
"response": {
"isSuccess": true,
"error": "",
"body": {
"count": 2,
"fields": [
{
"fieldId": 1,
"tabId": 100,
"title": "First Name"
},
{
"fieldId": 2,
"tabId": 100,
"title": "Last Name"
}
]
}
},
"iteration": {
"totalCount": 2,
"currentCount": 0,
"step": 1
}
}
I want to query the fields array as:
$.response.body.fields[$.iteration.currentCount]
The value of currentCount is incremented by 1 as part of an iteration.
I am getting an invalid XPath exception when trying to use the above.
Can someone please advice on how to provide a dynamic property value to read array values?
As described on https://github.com/json-path/JsonPath#operators you can index an array with a number only. However, you can use a filter expression to select a specific item from the array as follows.
Assuming you have another field that denotes the index such as:
{
"index": 0,
"fieldId": 2,
"tabId": 100,
"title": "Last Name"
}
You can then do
$.response.body.fields[?(#.index==$.iteration.currentCount)]

Gatling: JsonPath extract multiple values

I'm building a gatling 2.1.3 scenario and I need to extract data from a json body.
Example of the body:
[
{
"objectId": "FirstFoo",
"pvrId": "413"
"type": "foo",
"name": "the first name",
"fooabilities": {
"foo1": true,
"foo2": true
},
"versions": [23, 23, 23, 23, 23, 23, 24, 23, 23],
"logo": [
{
"type": "firstlogo",
"width": 780,
"height": 490,
"url": "firstlogos/HD/{resolution}.png"
}
]
},
{
"objectId": "SecondFoo",
"pvrId": "414"
"type": "foo",
"name": "the second name",
"fooabilities": {
"foo1": true,
"foo2": false
},
"versions": [23, 23, 23, 23, 23, 23, 24, 23, 23],
"logo": [
{
"type": "secondlogo",
"width": 780,
"height": 490,
"url": "secondlogos/HD/{resolution}.png"
}
]
}
]
and I have this code trying to extract de data:
exec(
http("get object")
.get(commons.base_url_ws + "/my-resource/2.0/object/")
.headers(commons.headers_ws_session).asJSON
.check(jsonPath("$..*").findAll.saveAs("MY_RESULT"))) (1)
.exec(session => {
foreach("${MY_RESULT}", "result") { (2)
exec(session => {
val result= session("result").as[Map[String, Any]]
val objectId = result("objectId")
val version = result("version")
session.set("MY_RESULT_INFO", session("MY_RESULT_INFO").as[List[(String,Int)]] :+ Tuple2(objectId, version))
})
}
session
})
My goal is:
To extract the objectId and the 9th value from the version array.
I want it to look as Vector -> [(id1, version1),(id2, version2)] in the session to reuse later in another call to the API.
My concerns are:
(1) Is this going to create entries in the session with the complete sub objects? Because in other answers I was that is was always a map that was saved ("id" = [{...}]) and here I do not have ids.
(2) In the logs, I see that the session is loaded with a lot of data, but this foreach is never called. What could cause this ?
My experience in Scala is of a beginner - there may be issues I did not see.
I have looked into this issue: Gatling - Looping through JSON array and it is not exactly answering my case.
I found a way to do it with a regex.
.check(regex("""(?:"objectId"|"version"):"(.*?)",.*?(?:"objectId"|"version"):\[(?:.*?,){9}([0-9]*?),.*?\]""").ofType[(String, String)].findAll saveAs ("OBJECTS")))
I can then use this
foreach("${OBJECTS}", "object") {
exec(
http("Next API call")
.get(commons.base_url_ws + "/my-resource/2.0/foo/${object._1}/${object._2}")
[...]
}