Accessing objects within nested loops using hashmap List - rest-assured

I have a JSON response which I want to parse and extract the data from. Here is the JSON response
[
{
"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 extract each od_pair and the values of of bucket and available within them.
#Fenio's solution in Accessing jsonpath elements with nested objects has the best approaches. The code snippet that I have refactored looks like this:
List<HashMap<String, Object>> LegList = jsonPath.getList("$");
for (HashMap<String, Object> singleLeg : LegList) {
String OD_pair = (String) singleLeg.get("od_pair");
//List<HashMap<String, Object>> bucketsList = jsonPath.param("j", j).getList("[j].buckets");
List<HashMap<String, Object>> bucketsList = jsonPath.getList("singleLeg.buckets");
for (HashMap<String, Object> singleBucket : bucketsList) {
String BucketCode = (String) singleBucket.get("bucket");
String Available = (String)
singleBucket.get("available");
I want to verify if the bucketsList that I am extracting is correct. Earlier I used a for loop with the parameter j. But with this approach which is lot more cleaner and nicer, I wish to understand if I am right in the way am extracting the bucketsList

I managed to resolve this. I understood where I was going wrong. Replacing
List<HashMap<String, Object>> bucketsList = jsonPath.getList("singleLeg.buckets");
with this
List<HashMap<String, Object>> bucketsList = (List<HashMap<String, Object>>) singleLeg.get("buckets");
Has resolved my issue and now things work as expected.
Since I was already within singleLeg loop, all I needed to call was the buckets object within the loop rather than trying to access the buckets from the rootpath.
Big shoutout to #Fenio who advised the best approaches in Accessing jsonpath elements with nested objects

Related

Converting http response to a Flutter list

I'm having trouble converting HTTP response body to a Flutter list. In a debugger, the output of jsonDecode(response.body)['data']['logsread'] looks exactly like
[
{
"id": "9fd66092-1f7c-4e60-ab8f-5cf7e7a2dd3b",
"email": "email#gmail.com"
}
]
Yet, this returns false.
print((jsonDecode(response.body)['data']['logsread']) ==
[{
"id": "9fd66092-1f7c-4e60-ab8f-5cf7e7a2dd3b",
"email": "email#gmail.com"
}]); // This returns false.
FYI. response.body =>
"{"data":{"logsread":[{"id":"9fd66092-1f7c-4e60-ab8f-5cf7e7a2dd3b","email":"email#gmail.com"}]}}"
JsonDecode returns List<dynamic> but your another list is of type List<Map<String,String>>. So convert it to same type of list by creating to any Model and overriding == and hashcode.
and to compare two list you need ListEquality function.
example :
Function eq = const ListEquality().equals;
print(eq(list1,list2));
I tried your code and done my way, check if this okay.
Model class:
class Model {
String id;
String email;
Model({
this.id,
this.email,
});
factory Model.fromJson(Map<String, dynamic> json) => new Model(
id: json["id"],
email: json["email"],
);
Map<String, dynamic> toJson() => {
"id": id,
"email": email,
};
#override
bool operator ==(Object other) =>
identical(this, other) ||
other is Model &&
runtimeType == other.runtimeType &&
id == other.id &&
email == other.email;
#override
int get hashCode =>
id.hashCode ^
email.hashCode;
}
main.dart
import 'package:collection/collection.dart';
var body =
'{"data":{"logsread":[{"id":"9fd66092-1f7c-4e60-ab8f-5cf7e7a2dd3b","email":"email#gmail.com"}]}}';
var test1 = (jsonDecode(body)['data']['logsread'] as List)
.map((value) => Model.fromJson(value))
.toList();
var test2 = ([
{"id": "9fd66092-1f7c-4e60-ab8f-5cf7e7a2dd3b", "email": "email#gmail.com"}
]).map((value)=>Model.fromJson(value)).toList();
Function eq = const ListEquality().equals;
print(eq(test1,test2));
I hope this is what you are looking for.
You should also provide position of the object you want to retrieve id from. Did you try doing this?
Example:
var id = ['data']['logsread'][0]['id'];
var email= ['data']['logsread'][0]['email'];
I mostly do this.
Your parse is correct, but I think that's not the right way to compare list of maps.
I think that doing == you're simply comparing the objects and not their content.
I suggest you to check here for map compare and here for list compare.
This way you would be checking the contents, and not roughly the objects (which are two different instances, so yeah technically they're different even if they have the same contents).
Try to first convert into the map and then use
import 'dart:convert';
//Decode response string to map
Map<String, dynamic> map = json.decode("jsonString");
xyz = map['data']['logsread'];

Push objects into array in Dart

List returnMovies = [];
Future<List> _getData() async {
final response = await http.get("https:../getTodayMovies",
headers: {HttpHeaders.AUTHORIZATION: Acess_Token.access_token});
if (response.body != null) {
returnMovies = json.decode(response.body);
.....
setState(() {});
} else {
final responseUpcoming = await http.get("/upcoming",
headers: {HttpHeaders.AUTHORIZATION: Acess_Token.access_token});
returnMovies = json.decode(responseUpcoming.body);
}
The response.body looks like:
[{"id":394470548,"host_group_name":"heyab redda","movie_image":"..png","type":"horror","code":"X123","name":"Lovely","start_time":1554364800,"end_time":1554393600,"}]
The responseUpcoming.body looks like:
{"id":394470545,"host_group_name":"foo redda","movie_image":".png","type":"horror","code":"X123","name":"Lovely","start_time":1554364800,"end_time":1554393600,"}, {"id":394470548,"host_group_name":"foo1 redda","movie_image":"..png","type":"comic","code":"X125","name":"Lovely1","start_time":1554364800,"end_time":1554393600,"}
The error I get is: String, dynamic is not a subtype of type List<dynamic>.
In the first API call that I am doing I normally get in return an array of objects, however, when this is empty, the second API call returns a list of objects that I want to push into the array called returnMovies, how can I achieve this?? Is there any way to .push these objects in the array?? So then I want to use this array to build dynamically a Listview.builder.
Also is it correct the way I am declaring it? I am quite new on Dart. Thank you
Sounds like you are looking for addAll
returnMovies.addAll(json.decode(returnUpcoming.body))
I will suggest to use
returnMovies.addAll({your object here})
When you do this json.decode(response.body) you are getting a List of Map you should use List<dynamic> movieListData and get the items like this:
movieListData = json.decode(response.body);
returnMovies = movieListData.map((dynamic movieData) {
String id = movieData['_id'];
String host_group_name = movieData['host_group_name'];
String duration = movieData['duration'];
return new Movie(id,title, duration);
}).toList();

Handle Double.NaN from Java to C# using snakeyaml (Java) and YamlDotNet (C#)

I'm using YAML to communicate between C# GUI and server side Java, which is working fine in general. However, if I pass a field that is a Double and the value is Double.NaN on Java side the Yaml passes as ".NaN", and when I come to deserialize on the C# side a 'System.FormatException' is thrown as C# expects the string "NaN" [not ".NaN"].
Does anyone know if there is a way to intercept the deserializer, or add formatting so that on the C# side ".NaN" can be parsed in a double?
(One workaround I can think of is changing all NaN's to a special value before serliazing to YAML, and then on C# recognizing the special value and converting back to NaN, but this seems like a big hack.)
It seems that this is a bug in the way YamlDotNet handles floats. Until it is fixed, you can work around it by registering a custom node INodeDeserializer that will handle these special cases.
Here is a quick-and-dirty implementation of such a deserializer:
public class FloatNodeDeserializer : INodeDeserializer
{
private static readonly Dictionary<Tuple<Type, string>, object> SpecialFloats =
new Dictionary<Tuple<Type, string>, object>
{
{ Tuple.Create(typeof(float), ".nan"), float.NaN },
{ Tuple.Create(typeof(float), ".inf"), float.PositiveInfinity },
{ Tuple.Create(typeof(float), "-.inf"), float.NegativeInfinity },
{ Tuple.Create(typeof(double), ".nan"), double.NaN },
{ Tuple.Create(typeof(double), ".inf"), double.PositiveInfinity },
{ Tuple.Create(typeof(double), "-.inf"), double.NegativeInfinity },
};
bool INodeDeserializer.Deserialize(
EventReader reader,
Type expectedType,
Func<EventReader, Type, object> nestedObjectDeserializer,
out object value
) {
var scalar = reader.Peek<Scalar>();
if (scalar == null) {
value = null;
return false;
}
var found = SpecialFloats.TryGetValue(
Tuple.Create(expectedType, scalar.Value),
out value);
if(found) {
reader.Allow<Scalar>();
}
return found;
}
}
The way to register it is:
var deserializer = new Deserializer();
deserializer.NodeDeserializers.Insert(0, new FloatNodeDeserializer());
See a fully working fiddle here

How do I pass my data to a JsonResult so that it formats correctly

I am using a MooTools TextboxList in my MVC app to create an autocomplete Tag suggester, similar to the StackOverflow one.
The script uses Json to do the suggestions. The Json string it seems to expect is different than I am able to generate. From the script's demo, it should look something like this:
[[32,"Science",null,null]]
But I can't figure out how to get the string to come out of MVC quite like that. Best I get looks more like:
[{"id":11,"text":"Science"}]
With the actual field names showing up.
Here is my controller method:
public JsonResult Suggest(string search)
{
JsonResult jsonresult = new JsonResult();
var tags = from t in db.Tags
where t.Text.Contains(search)
select new {id=t.TagID, text=t.Text};
var result = DoSomethingTo(tags); // <---????????
jsonresult.Data = result;
jsonresult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return jsonresult;
}
I've tried several variations of passing variables into the JsonResult.Data without much luck. I've tried arrays, custom objects, etc. I'm just not getting it. I'm certain it's very
Edit: That should have said "I'm certain it's very easy."
It's an array of arrays of objects. You could generate it like this:
return Json(new[] { new object[] { 32, "Science", null, null } });
and within your select action you could try something along the lines of:
public ActionResult Suggest(string search)
{
var tags = from t in db.Tags
where t.Text.Contains(search)
select new object[] { t.TagID, t.Text };
return Json(tags.ToList(), JsonRequestBehavior.AllowGet);
}
Based on another question, I ended up going old-school on it... building the string manually.
public ContentResult Suggest(string search)
{
var tags = from t in db.Tags
where t.Text.Contains(search)
orderby (t.Text)
select t;
var builder = new StringBuilder();
builder.Append("[");
foreach (Tag tag in tags)
builder.AppendFormat("[{0}, \"{1}\", null, null]", tag.TagID, tag.Text);
var result = builder.ToString().TrimEnd(new char[] { ',', ' ' }) + "]";
ContentResult res = new ContentResult();
res.Content = result;
return res;
}

JSON serialization, returning keys that have dashes in them?

I would like to return JSON from my controller which was generated from an anonymous type and contains dashes in the key names. Is this possible?
So if I have this:
public ActionResult GetJSONData() {
var data = new { DataModifiedDate = myDate.ToShortDateString() };
return Json(data);
}
On the client side I would like it to arrive serialized like this:
{ "data-modified-date" : "3/17/2011" }
My reason for wanting this is this Json data will ultimately become attributes on a DOM node, and I want to play nice and use the new HTML5 data attributes. I can just return { modifieddate: "3/17/2011" } and use it this way, but if I can become that little bit more conforming to standards I'd like to be.
I understand if I write my own JsonResult class that uses the WCF JSON Serializer on a non anonymous type, I can use theDataMemberAttribute to accomplish this. But that's a lot of overhead for such a simple desire.
I could also have the client massage the keys for me once it receives the data, but I'm hoping to avoid that too. All in all I'd rather just not follow standards than either of these workarounds.
You could use Json.NET and have full control over property names:
public ActionResult GetJSONData()
{
var obj = new JObject();
obj["data-modified-date"] = myDate.ToShortDateString();
var result = JsonConvert.SerializeObject(obj);
return Content(result, "application/json");
}
Obviously this code is screaming to be improved by introducing a custom action result:
public class JsonNetResult : ActionResult
{
private readonly JObject _jObject;
public JsonNetResult(JObject jObject)
{
_jObject = jObject;
}
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.Response;
response.ContentType = "application/json";
response.Write(JsonConvert.SerializeObject(_jObject));
}
}
and then:
public ActionResult GetJSONData()
{
var obj = new JObject();
obj["data-modified-date"] = myDate.ToShortDateString();
return new JsonNetResult(obj);
}
I found the JavaScriptSerializer that JsonResult uses has a special case for Dictionaries. So if you just do:
var data = new Dictionary<string, string>
{
{ "data-modified-date", myDate.ToShortDateString() }
};
Then the resulting JSON is in the desired format.

Resources