|
I noticed that it will fail when there are some emotes or extra characters are present in the string, there needs to be some sort of sanitization or something.
|
|
|
|
|
Hello!
I love this JSON parser, its easy. However I have noticed that it will fail if the JSON response is large. Can you fix this please?
Tony
|
|
|
|
|
This is awesome! It works and its straight forward. One issue though, it will fail when there is a large JSON response, and sometimes if there are text emotes.
|
|
|
|
|
|
Thanks for writing this useful code.
Here's a new method I've added to the JsonParser class:
Public Function JsonNextItem(dictInput As Object, item As String, ByVal tokens As Object) As Object
Set JsonNextItem = JsonDictionary(dictInput.item(item), tokens)
If JsonNextItem.Count = 0 Then Set JsonNextItem = JsonList(dictInput.item(item), tokens)
End Function
It returns the next JSON object item, whether that is a JsonDictionary object or a JsonList object. It means the programmer doesn't have to concern themselves whether the next JSON object is a named item or a list item. We can use it like this (replacing your code to search for latitude and longitude):
Dim dict As Object
Dim lat As Double, lng As Double
Set dict = tokenizer.JsonDictionary(tokenized, tokens)
Set dict = tokenizer.JsonNextItem(dict, "results", tokens)
Set dict = tokenizer.JsonNextItem(dict, "0", tokens)
Set dict = tokenizer.JsonNextItem(dict, "geometry", tokens)
Set dict = tokenizer.JsonNextItem(dict, "location", tokens)
lat = tokenizer.JsonDouble(dict.item("lat"), tokens)
lng = tokenizer.JsonDouble(dict.item("lng"), tokens)
What would be really useful, and a refinement of the above, would be a function which accepts a JSON 'XPath' string to return a specific value, instead of having to make a series of calls to drill down to the required value. Something like this:
lat = tokenizer.JsonXPath(dict, "results.0.geometry.location.lat", tokens)
lng = tokenizer.JsonXPath(dict, "results.0.geometry.location.lng", tokens)
modified 5-Dec-12 12:50pm.
|
|
|
|
|
Hi again,
What would be the most efficient way to iterate through such a list and build an Excel worksheet with only the "name" field going into sequential rows?
{
"data":[
{
"ID":"4f0f445c00253df3d70c2f473e96dfc1",
"name":"Project 1",
"objCode":"PROJ"
},
{
"ID":"4f3a5ff90016df6f230137dc9e33747f",
"name":"Project 2",
"objCode":"PROJ"
},
{
"ID":"4f0dd32c003a0473ca568ce4a9f42fb4",
"name":"Project 3",
"objCode":"PROJ"
},
{
"ID":"4f329cec002645386edb90978aaf5688",
"name":"Project 4",
"objCode":"PROJ"
},
]
}
I have tried this segment of code but keep getting buffer overflows or errors.
Dim tokens As Object
Dim tokenized As String
tokenized = tokenizer.JsonTokenize(response, tokens)
Dim dictA As Object
Set dictA = tokenizer.JsonDictionary(tokenized, tokens)
Dim listB As Object
Set listB = tokenizer.JsonList(dictA.Item("data"), tokens)
Dim nProjects As Integer
nProjects = 0
While nProjects < listB.Count
Dim dictC As Object
Set dictC = tokenizer.JsonDictionary(listB.Item(nProjects), tokens)
Cells(nProjects + 5, 1) = tokenizer.JsonString(dictC.Item("0"), tokens)
nProjects = nProjects + 1
Wend
Thanks,
-Haniel
|
|
|
|
|
I don't see anything fundamentally wrong with the code. One thing I learned was the script engine for applications (VBA) is not very robust.
I can make one stab at a solution, though. Move the Dim dictC out of While loop and put it before the While loop. Re-defining dictC over and over may be giving the VBA script engine fits. It is just a guess.
|
|
|
|
|
Hi Vinolarium,
I am trying to use your library in Excel to retrieve REST information from AtTask. I haven't used JSON before and have a question. When I log in successfully, I get back something like
{"data":{"userID":"4fe238140003732a9cad745b2e8b1cd9","sessionID":"08aebf7e323b4ac48bccee3b6a101834","versionInformation":{"currentAPI":"v2.0","buildNumber":"22c952e12dc10a586d8f2f0badb4dbfd894fc6f1","apiVersions":{"v1.0":"\/attask\/api\/v1.0\/","v2.0":"\/attask\/api\/v2.0\/"},"lastUpdated":"2012\/10\/05 15:25:09","release":"R16","version":"4.0"},"locale":"en_US","timeZone":"US\/Eastern","timeZoneName":"Eastern Standard Time","iso3Country":"USA","iso3Language":"eng","currency":{"useNegativeSign":false,"fractionDigits":2,"symbol":"$","ID":"USD","groupingSeparator":",","decimalSeparator":"."}}}
When login is unsuccessful, I get back something like this:
{"error":{"class":"com.attask.common.AuthenticationException","message":"That username\/password combination wasn't quite right. Make sure your caps lock isn't on."}}
Is there a way to pick out the "data" or "error" tags? Also, if I get the error tag, how do I retrieve the message? I tried the following but it didn't work.
Dim tokens As Object
Dim tokenized As String
tokenized = tokenizer.JsonTokenize(response, tokens)
Dim dictA As Object
Set dictA = tokenizer.JsonDictionary(tokenized, tokens)
Dim sTest As String
sTest = tokenizer.JsonString(dictA.Item("message"), tokens)
Thanks,
-Haniel
|
|
|
|
|
Hi I was wondering how you would handle the "types" : [ "country", "political" ]
tagging from the google response
|
|
|
|
|
As an example, the call for One Microsoft Way looks like this
http://maps.googleapis.com/maps/api/geocode/json?address=One+Microsoft+Way,Redmond,WA&sensor=false
and results I get start out like this:
{
"results" : [
{
"address_components" : [
{
"long_name" : "157th Ave NE",
"short_name" : "157th Ave NE",
"types" : [ "route" ]
},
{
"long_name" : "King",
"short_name" : "King",
"types" : [ "administrative_area_level_2", "political" ]
},
{
"long_name" : "Washington",
"short_name" : "WA",
"types" : [ "administrative_area_level_1", "political" ]
},
{
"long_name" : "United States",
"short_name" : "US",
"types" : [ "country", "political" ]
}
],
I am not totally sure what you are asking, but I think what you want is to see what would be necessary to grab the "United States" and "US" part.
There are two ways you can handle this. The simplest is to assume that the piece you want will always be the 4th element of the "address_components" list. A more robust approach is to specifically look for the "country", "political" piece and not assume it is always the 4th. I would personally choose the more robust approach.
Dim tokens As Object
Dim tokenized As String
tokenized = tokenizer.JsonTokenize(response, tokens)
Dim dictA As Object
Set dictA = tokenizer.JsonDictionary(tokenized, tokens)
Dim listB As Object
Set listB = tokenizer.JsonList(dictA.Item("results"), tokens)
Dim dictC As Object
Set dictC = tokenizer.JsonDictionary(listB.Item("0"), tokens)
Dim listComponents As Object
Set listComponents = tokenizer.JsonList(dictC.Item("address_components"), tokens)
Dim dictComponent As Object
Dim listTypes As Object
Dim firstType As String
Dim country As String
Dim longName As String
Dim shortName As String
Dim index As Integer
Set index = 0
While index < listX.Count
Set dictComponent = tokenizer.JsonDictionarylistComponents.Item(index.ToString()), tokens)
Set listTypes = tokenizer.JsonList(dictComponent.Item("types"), tokens)
Set firstType = listTypes.Item("0", tokens)
If firstType = "country" Then
Exit While
End If
Set index = index + 1
End While
If index < listX.Count Then
Set longName = tokenizer.JsonString(dictComponent.Item("long_name"), tokens)
Set shortName = tokenizer.JsonString(dictComponent.Item("short_name"), tokens)
End If
|
|
|
|
|
Thank you for the quick response.
What I was wondering about is how to parse:
"types" : [ "country", "political" ]
Is it possible to do something like this with a parse? I have an app returning this:
{ "results": [[1.1,1.2,1.3],[2.1,2.2,2.3]]}
basically I want to be able to :
in one looping display
1.1
1.2
1.3
2nd looping display
2.1
2.2
2.3
your help would be greatly appreciated
|
|
|
|
|
OK, for the JSON you provided, you have:
* Outermost is a dictionary, which contains a "results" entry
* The "results" entry returns a list of lists of decimals (or you could treat them as strings)
Here is some code to get you started. Sorry it's not debugged (and I forgot if there is a JsonFloat method you could call instead of JsonString at the end). But it should be pretty close.
Dim dictA As Object
Set dictA = tokenizer.JsonDictionary(tokenized, tokens)
Dim listResults As Object
Set listResults = tokenizer.JsonList(dictA.Item("results"), tokens)
Dim listDecimals As Object
Dim outer As Integer
Set outer = 0
Dim inner As Integer
Dim dataAsString As String
While outer < listResults.Count
Console.WriteLine("List " + outer.ToString())
Set listDecimals = tokenizer.JsonList(listResults.Item(outer.ToString()), tokens)
Set inner = 0
While inner < listDecimals.Count
Set dataAsString = tokenizer.JsonString(listDecimals.Item(inner.ToString()), tokens)
Console.WriteLine(dataAsString)
inner = inner + 1
End While
outer = outer + 1
End While
|
|
|
|
|
Hey cool! Thank you! I was doing step by step in my post below and then noticed your response!
|
|
|
|
|
I was able to do the following....
Dim response As String
response = "{ ""results"": [[1.1,2.2,3.3],[4.4,5.5,6.6]]}"
Dim tokens As Object
Dim tokenized As String
tokenized = tokenizer.JsonTokenize(response, tokens)
Dim dictA As Object
Set dictA = tokenizer.JsonDictionary(tokenized, tokens)
Debug.Print "result set: " + dictA.Item("results")
Set resultList = tokenizer.JsonList(dictA.Item("results"), tokens)
Debug.Print resultList.Count
Debug.Print "0: " & resultList.Item("0")
Debug.Print "1: " & resultList.Item("1")
Set list = tokenizer.JsonList(resultList.Item("0"), tokens)
Debug.Print "0: " & tokenizer.JsonString(list.Item("0"), tokens)
Debug.Print "1: " & tokenizer.JsonString(list.Item("1"), tokens)
Debug.Print "2: " & tokenizer.JsonString(list.Item("2"), tokens)
Set list = tokenizer.JsonList(resultList.Item("1"), tokens)
Debug.Print "0: " & tokenizer.JsonString(list.Item("0"), tokens)
Debug.Print "1: " & tokenizer.JsonString(list.Item("1"), tokens)
Debug.Print "2: " & tokenizer.JsonString(list.Item("2"), tokens)
|
|
|
|
|