Add item to JSON array using JsonPatchDocument - json

I am trying to add an element to a JSON array using Microsoft's JsonPatch implementation in .NET 6:
JSON input:
{ "foo": [ 1 ] }
Expected JSON output:
{ "foo": [ 1, 2 ] }
Following their documentation, I ended up with the following code:
string input = #"{ ""foo"": [ 1 ] }";
dynamic obj = JsonSerializer.Deserialize<ExpandoObject>(input);
var patch = new JsonPatchDocument();
patch.Add("/foo/-", 2);
string output = JsonSerializer.Serialize(obj);
Console.WriteLine(output); // throws JsonPatchException, expected { "foo": [ 1, 2 ] }
I expect the foo property of my object to contain an array equal to [1, 2], but instead it fails with the following error:
Microsoft.AspNetCore.JsonPatch.Exceptions.JsonPatchException: The target location specified by path segment '-' was not found.
A Replace operation on the foo property successfully updates the ExpandoObject, but the Add operation fails. Am I missing something obvious?
I also tried using JsonNode instead of ExpandoObject to no avail (JsonNode obj = JsonSerializer.Deserialize<JsonNode>(input);). The code throws the same error.

In the meantime, as a workaround, I am using JsonPatch.Net. The code looks similar:
string input = #"{ ""foo"": [ 1 ] }";
JsonNode obj = JsonSerializer.Deserialize<JsonNode>(input);
var patch = new JsonPatch(PatchOperation.Add(JsonPointer.Parse("/foo/-"), 2));
PatchResult patchResult = patch.Apply(obj);
string output = JsonSerializer.Serialize(patchResult.Result);
Console.WriteLine(output); // { "foo": [ 1, 2 ] }

Related

Unable to extract json response

I am trying to extract a JSON response.When I try to access the object within the json array it returns undefined
weather= [{"id":711,"main":"Smoke","description":"smoke","icon":"50d"}]
var x=JSON.stringify(weather)
x[0].main= returns =>undefined
You can simply use Array#map OR Array#forEach function to get all you JSON data. You do not need to use JSON.stringify in your response.
Demo:
let weather = [{
"id": 711,
"main": "Smoke",
"description": "smoke",
"icon": "50d"
}]
weather.map(function(x) {
console.log(x.id) //711
console.log(x.main) //Smoke
console.log(x.description) //smoke
console.log(x.icon) //50d
})
I'm not sure what you're trying to accomplish or what you've tried, but here is how that works:
const weather = [{"id":711,"main":"Smoke","description":"smoke","icon":"50d"}]
document.querySelector('#id').textContent = weather[0].id
document.querySelector('#json').textContent = JSON.stringify(weather)
ID:
<div id="id"></div>
Stringified JSON:
<div id="json"></div>
To access an element of an array you can reference an index or loop through it:
const myArray = [1, 2, 3];
myArray[0] // 1
myArray[1] // 2
myArray[2] // 3
for (let i = 0 ; i < myArray.length ; i++) {
console.log(myArray[i]);
}
To access a property of an object you can either use dot notation or the key name as the index:
const myObject = {'a': 1, 'b': 2}
myObject.a // 1
myObject['b'] // 2
JSON.stringify converts your JSON into a string. This is useful for sending it over a connection to a host that may or may not recognize JSON.

Extract multiple JsonPath values from returned Response using Rest Assured

I need to obtain two values from JSON response data returned from a Rest Assured modelled request:
public void getCustomerStatuses() {
Response response =
given().header("X-AC-User-ID","test-user").
spec(customerApiSpec).
when().
get("/api/v6/status/" + ref + "/").
then().
assertThat().statusCode(200).extract().response();
custStatusId = response.path("$.cust[?(#.name=='STATUS_ID')].id");
custRenewalId = response.path("$.cust[?(#.name=='RENEWAL_ID')].id");
System.out.println(custStatusId);
System.out.println(custRenewalId);
}
This throws and java.lang.IllegalArgumentException: Invalid JSON expression:Script1.groovy: 1: Unexpected input: '$.cust[?' # line 1, column 36. $.cust[?(#.name=='STATUS_ID')].id
What is the correct, best way of obtaining these? I'm aware I can chain extract().response().jsonPath(); off the request but not sure how I can obtain >1 value
Yes you can use JsonPath
Response response =
given().header("X-AC-User-ID","test-user").
spec(customerApiSpec).
when().
get("/api/v6/status/" + ref + "/").
then().
assertThat().statusCode(200).extract().response();
JsonPath jsonPath = response.jsonPath();
If the received json body is this;
{
"value1":{
"id": 1,
"abc": {
"v1": "o1",
"v2": "o2"
}
},
"value2":{
"id": 2,
"title": "test2"
}
}
Then use the get(String path) method;
String v1 = jsonPath.get("value1.abc.v1"); // o1
String title = jsonPath.get("value2.title"); // test2
Required import;
io.restassured.path.json.JsonPath;

Extract value from nested json in terraform

In terraform I have an external data source
data "external" "example" {
program = [
"some_program_generating_json"
]
}
some_program_generating_json produces the following output:
{
"dict1": {
"key1": "value1"
},
"dict2": {
"key1": "value2"
}
}
How can I extract the value of [dict1][key1] from that data source and assign it to some local?
lets say:
locals {
extracted_value = ???
}
Thanks.
I tested it, and had no problems using [dict1][key1] notation. This is the example I used.
script file (test.sh)
#!/usr/bin/bash
# from https://github.com/hashicorp/terraform/issues/13991#issuecomment-526869879
printf '{"base64_encoded":"%s"}\n' $(echo '{"dict1": {"key1": "value1"}, "dict2": {"key1": "value2"}}' | base64 -w 0)
main.tf
data "external" "example" {
program = [
"${path.module}/scripts/test.sh"
]
}
locals {
json_value = jsondecode(base64decode(data.external.example.result["base64_encoded"]))
dict1_key1 = local.json_value["dict1"]["key1"]
}
output "result" {
value = local.dict1_key1
}
The output was:
result = value1
Seems like I figured it out. I had to convert values of dict1 and dict2 to strings:
{
"dict1": "{\"key1\": \"value1\"}",
"dict2": "{\"key1\": \"value2\"}"
}
and then use jsondecode on them. I.e.
locals {
key = "dict1"
extracted_dict = jsondecode("${data.external.example.result[local.key]}")
extracted_value = local.extracted_dict["key1"]
}

Getting element value from jsonpath whose root is an array

I have a JSON response which has root as an array of 1 or more objects. I want to extract the value of one of the elements within each object.
Here is the JSON sample:
[
{
"od_pair":"7015400:8727100",
"buckets":[
{
"bucket":"C00",
"original":2,
"available":2
},
{
"bucket":"A01",
"original":76,
"available":0
},
{
"bucket":"B01",
"original":672,
"available":480
}
]
},
{
"od_pair":"7015400:8814001",
"buckets":[
{
"bucket":"C00",
"original":2,
"available":2
},
{
"bucket":"A01",
"original":40,
"available":40
},
{
"bucket":"B01",
"original":672,
"available":672
},
{
"bucket":"B03",
"original":632,
"available":632
},
{
"bucket":"B05",
"original":558,
"available":558
}
]
}
]
I want to access the values of od_pair within each object.
I tried referring to the root array as $ but that did not help.
This is the code snippet I have written:
List<Object> LegList = jsonPath.getList("$");
int NoofLegs = LegList.size();
System.out.println("No of legs :" +NoofLegs);
for (int j=0; j<=NoofLegs;j++) {
String OD_Pair = jsonPath.param("j", j).getString("[j].od_pair");
System.out.println("OD Pair: " + OD_Pair);
List<Object> BucketsList = jsonPath.param("j", j).getList("[j].buckets");
int NoOfBuckets = BucketsList.size();
System.out.println("no of Buckets: " + NoOfBuckets);
}
This is the error that I see:
Caused by:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup
failed:
Script1.groovy: 1: unexpected token: [ # line 1, column 27.
restAssuredJsonRootObject.[j].od_pair
Can someone kindly help me here please?
You were right to start with the $. However, What you get with your particular JSON is List of HashMap<String, Object> where each JSON Object is represented as a single HashMap. Knowing that you can obtain the list of HashMaps like this:
List<HashMap<String, Object>> jsonObjectsInArray = path.getList("$");
The String will be the name of the attribute. The Object will be either String, Integer, JSONObject or JSONArray. The latter isn't exact class names but it's not relevant to you to achieve desired results.
Now, all we have to do is iterate over the HashMap and extract values of od_pair like this:
for (HashMap<String, Object> jsonObject : jsonObjectsInArray) {
System.out.println(jsonObject.get("od_pair"));
}
The output is:
7015400:8727100
7015400:8814001
Hope it helps!

Parsing JSON with Dart

I want to be able to parse a string to an object that I can access using the dot notation e.g. myobject.property, instead of the array notation e.g. myobject['property']. The array notation works fine. Here's what I have so far.
I have some XML:
<level1 name="level1name">
<level2 type="level2Type">
<entry>level2entry</entry>
<entry>level2entry</entry>
</level2>
</level1>
Which converts to the JSON:
{
"level1": {
"name": "level1name",
"level2": {
"type": "level2Type",
"entry": [
"level2entry",
"level2entry"
]
}
}
}
I have the following Dart code:
Object jsonObject = JSON.parse("""{
"level1": {
"name": "level1name",
"level2": {
"type": "level2Type",
"entry": [
"level2entry",
"level2entry"
]
}
}
}
""");
print("my test 1 == ${jsonObject}");
print("my test 2 == ${jsonObject['level1']}");
print("my test 3 == ${jsonObject['level1']['name']}");
which produce the (desired) output:
my test 1 == {level1: {name: level1name, level2: {type: level2Type, entry: [level2entry, level2entry]}}}
my test 2 == {name: level1name, level2: {type: level2Type, entry: [level2entry, level2entry]}}
my test 3 == level1name
But when I try:
print("my test 1 == ${jsonObject.level1}");
I get the following:
Exception: NoSuchMethodException : method not found: 'get:level1'
Receiver: {level1: {name: level1name, level2: {type: level2Type, entry: [level2entry, level2entry]}}}
Arguments: []
Stack Trace: 0. Function: 'Object.noSuchMethod' url: 'bootstrap' line:717 col:3
Ideally, I want an object that I can access using the dot notation and without the compiler giving warning about Object not having property. I tried the following:
class MyJSONObject extends Object{
Level1 _level1;
Level1 get level1() => _level1;
set level1(Level1 s) => _level1 = s;
}
class Level1 {
String _name;
String get name() => _name;
set name(String s) => _name = s;
}
...
MyJSONObject jsonObject = JSON.parse("""{
"level1": {
"name": "level1name",
"level2": {
"type": "level2Type",
"entry": [
"level2entry",
"level2entry"
]
}
}
}
""");
...
print("my test 1 == ${jsonObject.level1.name}");
but instead of giving me 'level1name' as hoped, I get:
Exception: type 'LinkedHashMapImplementation<String, Dynamic>' is not a subtype of type 'MyJSONObject' of 'jsonObject'.
What am I doing wrong here? Is there any way to do what I'm trying? Thanks.
At the moment, JSON.parse only returns Lists (array), Maps, String, num, bool, and null
(api ref).
I suspect that until reflection makes it way into the language, it won't be able to re-construct objects based upon the keys found in json.
You could, however, create a constructor in your MyJsonObject which took a string, called JSON.parse internally, and assigned the various values.
Something like this works in the dart editor:
#import("dart:json");
class Level2 {
var type;
var entry;
}
class Level1 {
var name;
var level2;
}
class MyJSONObject {
Level1 level1;
MyJSONObject(jsonString) {
Map map = JSON.parse(jsonString);
this.level1 = new Level1();
level1.name = map['level1']['name'];
level1.level2 = new Level2();
level1.level2.type = map['level1']['level2']['type'];
//etc...
}
}
main() {
var obj = new MyJSONObject(json);
print(obj.level1.level2.type);
}
A non trivial version would needs some loops and possible recursion if you had deeper nested levels.
Update: I've hacked together a non-trivial version (inspired by the post below), it's up on github (also taking Seth's comments re the constructor):
Chris is completely right. I will only add that the JSON parser could be modified to return a little richer object (something like JsonMap instead of pure Map) that could allow jsonObj.property by implementing noSuchMethod. That would obviously perform worse than jsonObj['property'].