I'm attempting to populate a table with the contents of a JSON file downloaded from S3 (using the AWS SDK). I'm having difficulty looping through the notifications array because it doesn't seem to be an iterable object. Nil is returned when typecasting the entire object to a dictionary. I received an error stating that I cannot typecast the notifications String as an array. How can I typecast the notifications object into something I can iterate?
//JSON file
{
"notifications": [
{
"startDate": "2016-10-01 00:00:00",
"endDate": "2016-10-31 23:59:59",
"message": "October"
},
{
"startDate": "2016-11-01 00:00:00",
"endDate": "2016-11-31 23:59:59",
"message": "November"
}
]
}
//I omitted extraneous code
let task = s3.getObject(getObjectRequest)
if let output = task.result as? AWSS3GetObjectOutput{
do{
let json = try NSJSONSerialization.JSONObjectWithData((output.body! as? NSData)!, options: .AllowFragments)
//Debug code that works
print(json["notifications"]![0]) //Prints the first notification
print(json["notifications"]![0]["startDate"])
//Debug code that does not work
let opt = json["notifications"] as! NSArray //Can't typecast String as Array
//A 'for' loop does not work as well.
}catch{
print("Error serializing JSON [\(error)]")
}
}
json["notifications"] as! NSArray works but you have to first cast the result of NSJSONSerialization to the right type, in your case a dictionary:
do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String:AnyObject] {
print(json["notifications"] as! NSArray)
}
} catch let error as NSError {
print(error.debugDescription)
}
or, if you prefer:
do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? NSDictionary {
print(json["notifications"] as! NSArray)
}
} catch let error as NSError {
print(error.debugDescription)
}
let opt = json["notifications"] as? Array //Can't typecast String as Array
Please try this
Related
I am deserializing some JSON objects which come in as requests. The input body is nested, but a certain field is sometimes misformatted for a variety of reasons. In that situation I still want the rest of the object. This doesn't all have to be done through serde; but what is happening now, is that if a single subfield is messed up, the whole request is trashed. I want to somehow still deserialize that result and just mark the field as errored out. How can this be done?
E.g. the data schema might look like:
struct BigNested {
a: Vec<A>,
b: B, // definition omitted
}
struct A {
keep_this: Foo,
trouble: SometimesBad,
}
trouble is the field that's frequently coming in messed up. I would be happy to (e.g.) turn trouble into a Result<SometimesBad, Whatever> and process it from there, but I don't know how to get serde to let me do that.
certain field is sometimes misformatted
You didn't say how malformed the incoming JSON was. Assuming it's still valid JSON, you can pull this off with Serde's struct flatten and customized deserialization:
The customized deserialization is done in a way that never fails for valid JSON input, although it may not return value of expected type if the input has unexpected format.
But these unexpected fields still need to go somewhere. Serde's struct flatten comes in handy here to catch them since any JSON snippet can be deserialized to a HashMap<String, Value>.
//# serde = { version = "1.0.103", features = ["derive"] }
//# serde_json = "1.0.44"
use serde::{Deserialize, Deserializer, de::DeserializeOwned};
use serde_json::Value;
use std::collections::HashMap;
#[derive(Deserialize, Debug)]
struct A {
keep_this: Foo,
trouble: SometimesBad,
}
#[derive(Deserialize, Debug)]
struct Foo {
foo: i32,
}
#[derive(Deserialize, Debug)]
struct SometimesBad {
inner: TryParse<Bar>,
#[serde(flatten)]
blackhole: HashMap<String, Value>,
}
#[derive(Deserialize, Debug)]
struct Bar {
bar: String,
}
#[derive(Debug)]
enum TryParse<T> {
Parsed(T),
Unparsed(Value),
NotPresent
}
impl<'de, T: DeserializeOwned> Deserialize<'de> for TryParse<T> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
match Option::<Value>::deserialize(deserializer)? {
None => Ok(TryParse::NotPresent),
Some(value) => match T::deserialize(&value) {
Ok(t) => Ok(TryParse::Parsed(t)),
Err(_) => Ok(TryParse::Unparsed(value)),
},
}
}
}
fn main() {
let valid = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "bar": "one"}}}"#;
println!("{:#?}", serde_json::from_str::<A>(valid));
let extra_field = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "bar": "one"}, "extra": 2019}}"#;
println!("{:#?}", serde_json::from_str::<A>(extra_field));
let wrong_type = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "bar": 1}}}"#;
println!("{:#?}", serde_json::from_str::<A>(wrong_type));
let missing_field = r#"{ "keep_this": { "foo": 1 }, "trouble": { "inner": { "baz": "one"}}}"#;
println!("{:#?}", serde_json::from_str::<A>(missing_field));
let missing_inner = r#"{ "keep_this": { "foo": 1 }, "trouble": { "whatever": { "bar": "one"}}}"#;
println!("{:#?}", serde_json::from_str::<A>(missing_inner));
}
(The credit isn't all mine. Serde's issue 1583 basically has everything.)
I am now working on a complex XML parsing.
Here is the link: https://www.reddit.com/hot/.rss
I use Alamofire to fetch data:
protocol APIUsable {
}
struct API: APIUsable {
static func fetchRedditFeedListData() -> Observable<[Entry]>{
let URL = "https://www.reddit.com/hot/.rss"
return Observable.create { observer in
Alamofire.request(URL).response { response in
guard let data = response.data else {
return
}
do {
let xml = SWXMLHash.parse(data)
let entries: [Entry] = try xml["feed"]["entry"].value()
observer.onNext(entries)
} catch let error as NSError {
print(error.localizedDescription)
}
observer.onCompleted()
}
return Disposables.create()
}
}
}
The following is the struct I build for parsing. And It works well.
struct Entry: XMLIndexerDeserializable {
let title: String
let updated: String
let category: String
let content: String
static func deserialize(_ node: XMLIndexer) throws -> Entry {
return try Entry(
title: node["title"].value(),
updated: node["updated"].value(),
category: node["category"].value(ofAttribute: "term"),
content: node["content"].value()
)
}
}
But I also want to get the image string belong to content, img, src
I have found the solution by myself.
As we can see that there is a HTML in a XML.
So, I use SWXMLHash again to parse content
let xml = SWXMLHash.parse(/*put the content String here*/)
let imageString = xml ["table"]["tr"]["td"][0]["a"]["img"].element?.attribute(by: "src")?.text
then we can get the value of src as string for future use
I have been working with Go and the Bitmex API.
I have the following Bitmex api endpoint:
https://www.bitmex.com/api/v1/leaderboard
This returns an array of JSON objects structured as follows.
[
{
"name": "string",
"isRealName": true,
"profit": 0
}
]
However I get the following incorrect representation of the JSON when I marshal it.
[{0 false } {0 false } ... ]
I know my HTTP request is going through, as when I print the response.Body I get the following
[{"profit":256915996199,"isRealName":true,"name":"angelobtc"} ... ]
Here is the struct I am using to store the marshaled data.
type LeaderboardResponse struct {
profit float64 `json:"profit"`
isRealName bool `json:"isRealName"`
name string `json:"name"`
}
And my main method
func main() {
response, errorResponse := http.Get("https://www.bitmex.com/api/v1/leaderboard")
if response.Status == "200 OK"{
if errorResponse != nil {
fmt.Printf("The HTTP request failed with error %s\n",errorResponse)
} else {
body, errorBody := ioutil.ReadAll(response.Body)
if errorBody != nil {
fmt.Println("There was an error retrieving the body", errorBody)
} else {
leaderboard := []LeaderboardResponse{}
json.Unmarshal([]byte(body),&leaderboard)
if leaderboard != nil {
fmt.Println(leaderboard);
//The result of the statement above and the one below are different
fmt.Println(string(body))
} else {
fmt.Println("leaderboard array is undefined")
}
defer response.Body.Close()
}
}
} else {
fmt.Println("Response received with status ", string(response.Status))
}
}
It appears that the values of struct have not been modifies despite it being assigned the marshaled JSON body
How do I fix this issue?
Furthermore,
How do I add my API credentials to the HTTP request?
How do I access the response header and marshal it?
I'm trying to get the changed value of a HTML-Node.
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if(mutation.addedNodes[0].data == "9"){
dostuff();
}
}
}
But javascript returns only an object and no array of
addedNodes.mutation.addedNodes[0]
prints out:
<TextNode textContent="9">
Where can I get the value of the changed HTML-Node?
Thanks alot.
Ok, found a solution via Stackoverflow
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
[].call(mutation.addedNodes).forEach(function (addedNode) {
if(addedNode.textContent == "9"){
dostuff();
}
});
});
});
I am hoping someone can help me. I trying to use SIOSocket with a Swift project.
I am using the example at https://github.com/MegaBits/SIOSocket/issues/30 which seems to work, but i want to be able to declare a socket as a var like the Objective-C project example at https://github.com/MegaBits/WorldPin. so i can use it in else where in the code to call emit.
I assume i am not understanding the Obj-C block and Swift closure fundamentals and the use of self or the need to declare the var as block but can’t seem to wrap my head around it. Any help will be much appreciated.
SIOSocket is on Github
Objective-C code:
#property SIOSocket *socket;
[SIOSocket socketWithHost: #"http://localhost:3000" response: ^(SIOSocket *socket)
{
self.socket = socket; //I Want to do this in swift
__weak typeof(self) weakSelf = self;
self.socket.onConnect = ^()
{
weakSelf.socketIsConnected = YES;
[weakSelf mapView: weakSelf.mapView didUpdateUserLocation: weakSelf.mapView.userLocation];
};
[self.socket on: #"join" callback: ^(SIOParameterArray *args)
{
[weakSelf mapView: weakSelf.mapView didUpdateUserLocation: weakSelf.mapView.userLocation];
}];
[self.socket on: #"update" callback: ^(SIOParameterArray *args)
{
NSString *pinData = [args firstObject];
etc etc …
Swift Code:
private func connectToHost() {
SIOSocket.socketWithHost(host, reconnectAutomatically: true, attemptLimit: 0, withDelay: 1, maximumDelay: 5, timeout: 20, response: {
socket in
self.socket = socket // This gives me a use of unresolved identifier self error
socket.onConnect = {
println("Connected to \(host)")
socket.emit("add user", args: [username])
}
socket.on("login", callback: {(AnyObject data) -> Void in
println(["login": data])
socket.emit("new message", args: [message])
})
socket.onDisconnect = {
println("Disconnected from \(host)")
}
})
}
Your code should work, make sure you have all the right types and optional types, make sure socket is a read-write variable by defining it with var and not with let.
Try defining the closure before the method call by using let response: (SIOSocket) -> Void = {...}.
Try changing it to this:
SIOSocket.socketWithHost(host, reconnectAutomatically: true, attemptLimit: 0, withDelay: 1, maximumDelay: 5, timeout: 20, response: {(socket: SIOSocket) in
self.socket = socket // This gives me a use of unresolved identifier self error
//...
})
I changed socket in to (socket: SIOSocket) in