I have some json that was returned from a web api with some null values. When I try to retrieve a key with null as the value I get an exception error and hangs the app. How do I avoid or deal with this situation?
{
“ship_to”: {
“name”: “Test Name”,
“phone”: “1234567890”,
“company_name”: null
}
}
Use JSONItem.Lookup
to provide a default value or handle the KeyNotFoundException
yourself.
http://documentation.xojo.com/index.php/JSONItem
It would help to show us the code that parses the JSON and retrieves the value, and where and what the exception is.
How about this? Works on my computer
dim js as new JSONItem(source)
dim shipTo as JSONItem = js.Value("ship_to")
MsgBox shipTo.Value("company_name")
So I figured out what the issue is. A json key with a value of null returns Nil.
This is the text of the json, is comes a curl command that was run as a Shell statement and is put into the Text variable called curl_buffer;
{
"ship_to": {
"name": "Test Name",
"phone": "1234567890",
"company_name": null
}
}
So the following creates a Type Exception
Dim json As Xojo.Core.Dictionary
json = Xojo.Data.ParseJSON(curl_Buffer)
Dim shipto As Xojo.Core.Dictionary = json.Value("ship_to)
Label1.Text = shipto.Value("name") // Wrong! causes application crash
If Label1.Text = shipto.Value("name") <> Nil Then // This works!
Label1.Text = shipto.Value("name")
Else
Label1.Text = ""
End If
Pretty simple issue, null or Nil is not the same as blank (""). I should have realized this from the start. While the solve is simple it’s wordy and there are many places where I will encounter a null value.
What complicated the issue for me is I found this nifty function and it works great but it will return the null, requiring me to still check for Nil;
Function DictionaryValue(Extends d As Xojo.Core.Dictionary, key As Auto) As Xojo.Core.Dictionary
return Xojo.Core.Dictionary( d.Value( key ) )
End Function
Which allows me to access the “name” value in a single statement like this.
Dim json As Xojo.Core.Dictionary
json = Xojo.Data.ParseJSON(curl_Buffer) // curl_buffer is text via curl Shell script
Label1.Text = json.DictionaryValue("ship_to").value("name") // Without the check for null this will fail.
So I want to modify the function to return “” when it encounters a null instead of Nil. Since this portion of the App is for viewing, blank values are acceptable and for the viewer to see, then determine what to do. I seem to be misunderstanding the function though. It keeps passing the Nil not matter what I try.
So put the value into a property of type Auto and then check its value for Nil before doing the assignment.
dim tmp as Auto = json.DictionaryValue("ship_to").value("name")
If tmp <> Nil then
Label1.Text = tmp
End if
I was about to go down that road, after a night of sleep… I realized what my function was doing and the fix is not there. All that function does is spin through the key levels to get to the lowest key that is holding the value I want. In this case “ship_to”, Its not actually retrieving the value in “name”.
So my Label1 assignment is using d.Value(key) which translates to ship_to.Value(“name”). In this case = Nil.
Once sleep deprivation is cleared. I then realized I have a module that will deal with this nicely. It will turn any Value into a Text value. Problem Solved!
I got so wrapped up in the first function I did not see the forest through the trees. So all I needed to do is change my code. Note Value() changes to ValueT;
Label1.Text = json.DictionaryValue("ship_to").ValueT("name") // Note ValueT("name")
The ValueT function takes any Key value and returns a Text value. So Nil becomes “”, no need to check for Nil in my assignment statement. Here is that function below;
Function ValueT(Extends dict As Xojo.Core.Dictionary, key As Text) As Text
// This method looks at the type of the dictionary value
// and returns it as a Text if it is Integer, Double, Boolean or Text
Dim value As Auto = dict.Value(key)
Dim info As Xojo.Introspection.TypeInfo
info = Xojo.Introspection.GetType(value)
Dim textValue As Text
Select Case info
Case GetTypeInfo(Integer)
Dim i As Integer = value
textValue = i.ToText
Case GetTypeInfo(Double)
Dim d As Double = value
textValue = d.ToText
Case GetTypeInfo(Text)
textValue = value
Case GetTypeInfo(Boolean)
Dim b As Boolean = value
If b Then
textValue = "True"
Else
textValue = "False"
End If
End Select
Return textValue
End Function
I have been coding Xojo since the beginning of January (2018) so please excuse these very Noob oversights.