Page 1 of 2

JSON files

Posted: Tuesday 12th September 2017 2:03pm
by cogier
I am trying to enumerate the 'Keys' in a Gambas decoded JSON file. If I run the code below I can print the data associated with the key but not the keys.

Code: Select all

Public Sub Main()
Dim vNew As Variant
Dim sNew As String

Shell "wget -O - https://poloniex.com/public?command=returnTicker" To sNew

vNew = Json.decode(sNew) ''Requires component 'gb.web'

Print vNew["BTC_BCN"]["last"]

Stop

End
I am looking to get a list of 'Keys' into an array ["BTC_BCN","BTC_BELA",...] and ["id","last","lowestAsk"...]. Any ideas appreciated.
Json1.png
Json1.png (66.75 KiB) Viewed 108 times

Re: JSON files

Posted: Tuesday 12th September 2017 8:50pm
by stevedee
Try this:-

Code: Select all

Public Sub Main()
Dim vNew As Variant
Dim sNew As String
Dim cBitcoin As Collection
Dim ciBitcoin As Collection

Shell "wget -O - https://poloniex.com/public?command=returnTicker" To sNew


vNew = Json.decode(sNew) ''Requires component 'gb.web'
cBitcoin = vNew

' Print cBitcoin.Length

For Each ciBitcoin In cBitcoin
  Print cBitcoin.Key, cBitcoin[cBitcoin.Key]["last"]
Next

Stop

End

Re: JSON files

Posted: Wednesday 13th September 2017 2:53pm
by cogier
Thanks SteveDee. There is no doubt that this works but I am having trouble getting my head around the logic. I haven't worked out how to get the next set of 'Keys', but this is a start, thanks. :?

Re: JSON files

Posted: Wednesday 13th September 2017 4:55pm
by stevedee
The clues are in your first post, but I don't know how much time you have spent playing around with Collections. As your screen shots show, vNew contains a collection of collections. Each trading pair in the collection contains its own collection of data, where the trading pair name is the Key string.

So I've taken the variant vNew (which is returned from Json.Decode) and copied it into the new collection cBitcoin. Then I enumerate each item in the collection cBitcoin by asking: "FOR EACH collection (ciBitcoin) IN the collection (cBitcoin) please return the Key"

The collection property cBitcoin.Key returns each collection key as a string (e.g. BTC_ETH). And then I can use:

Code: Select all

cBitcoin[cBitcoin.Key]["last"]
...to get the corresponding Last value.

In VB6 you could also access a collection using a numeric index, something like:

Code: Select all

strKeyName = cBitcoin[2].Name
...would give you the 3rd item Key in the collection. But Gambas does not support a numeric index.

I'm glad you used the Poloniex api query: "https://poloniex.com/public?command=returnTicker"
..as the main collection only references sub-collections, which makes the code straight forward.

As an additional exercise, I spent an hour or two this morning trying to do the same thing with:
"https://www.cryptocompare.com/api/data/coinlist/"
This collection includes a mixture of strings and collections, and I can't think how to deal with this.

What additional data are you trying to retrieve? The remaining data for each trading pair in your example is similar to "last". So for example, if you wanted the 24hr High value use:

Code: Select all

 cBitcoin[cBitcoin.Key]["high24hr"]
And if you want to filter trading pairs, you could just display Ether markets:

Code: Select all

For Each ciBitcoin In cBitcoin
  If InStr(cBitcoin.Key, "ETH") > 0 Then
    Print cBitcoin.Key, cBitcoin[cBitcoin.Key]["last"], cBitcoin[cBitcoin.Key]["high24hr"]
  Endif
Next
I hope this helps, but come back if its still gibberish.

Re: JSON files

Posted: Thursday 14th September 2017 1:19pm
by jornmo
As an additional exercise, I spent an hour or two this morning trying to do the same thing with:
"https://www.cryptocompare.com/api/data/coinlist/"
This collection includes a mixture of strings and collections, and I can't think how to deal with this.
I think that should be pretty easy actually. A recursive function to do the data extraction, and start it with a test like this:http://gambaswiki.org/wiki/lang/is

(Haven't actually run this code)
Public Sub GetCollectionData(Col as Collection)

  Dim v as Variant

  For Each v In Col
    If v Is Collection Then
      GetCollectionData(v)
    Else
      Print("Key: " & Col.Key & " Value: " & v
    End If

End Sub

Re: JSON files

Posted: Thursday 14th September 2017 2:43pm
by stevedee
Yes, I discussed it with #3 son last night (he is doing Computer Science at Uni, but does not code in Gambas) and this morning I came up with this:-

Code: Select all

  Shell "wget -O - https://www.cryptocompare.com/api/data/coinlist/" To sNew
  cBitcoin = Json.decode(sNew, True)

  For Each ciBitcoin In cBitcoin["Data"]
    strCrypto.Resize(intCoinCount + 1)
    strCrypto.Add(ciBitcoin["Name"] & ":" & ciBitcoin["CoinName"])
    Inc intCoinCount
  Next

  strCrypto.Sort	'sort them in alpha order
  For index = 0 To strCrypto.Count - 1
    Print strCrypto[index]
  Next
  Print "Total:", intCoinCount
Wow! there are 1507 cryptos listed on this site!

The important bit is the For Each line that just enumerates the "Data" object in the json text. The rest just puts the text into an array and creates pretty-text.

Re: JSON files

Posted: Thursday 14th September 2017 4:16pm
by cogier
This started with a question from Brad on the 'other' forum (which seems to be a forum no longer). I managed to sort the problem for which I recveived the heart warming "Awesome! Thank you so much!" but I thought I'd dig further and automatically get all the data into arrays. The URL I am using came from Brad.

Your solution worked but confused me as I have only ever enumerated with the variable after 'Each' not with the variable after 'In'

e.g.
For Each ciBitcoin In cBitcoin
Print ciBitcoin.Key
Next

But you worked with ciBitcoin, it works but I can't work out the logic here.

For Each ciBitcoin In cBitcoin
Print cBitcoin.Key
Next

I was trying to get a list of the other keys as well ["id","last",lowestAsk"...].

Using your example website you end up with a list of keys ["Response", "Message"..."Data"...] then ["LC", "HEAT", "EXB"...] and open up the Collection and there are more keys ["id", "Url", "ImageUrl"...].

Basically I can get the information out as I can see keys like "last" but I thought it would be nice for Gambas to get all that detail for me.

Re: JSON files

Posted: Thursday 14th September 2017 9:24pm
by stevedee
cogier wrote:
Thursday 14th September 2017 4:16pm
...Your solution worked but confused me as I have only ever enumerated with the variable after 'Each' not with the variable after 'In'

e.g.
For Each ciBitcoin In cBitcoin
Print ciBitcoin.Key
Next

But you worked with ciBitcoin, it works but I can't work out the logic here.

For Each ciBitcoin In cBitcoin
Print cBitcoin.Key
Next
Take a look at this For Each...In... example:-

Code: Select all

Public Sub Main()
Dim Cars As New Collection
Dim Make As String

  Cars["Ford"] = 2
  Cars["Audi"] = 1
  Cars["Jaguar"] = 4
  Cars["Lada"] = 3
  
  For Each Make In Cars
    Print Make;
  Next
End 

This "Cars" collection consists of 4 string elements, each one has an integer value assigned to it.
We could print the integer value of an individual element by directly addressing the element, e.g.

Code: Select all

Print Cars["Lada"]
...would result in: 3

But by creating a string variable ("Make") we can specify that we want to step through each string element in Cars, assign it to Make and then print the corresponding integer value for Make. The result is that the integers are printer in the order they appear in the collection: 2 1 4 3

In the Crypto example, I am not looking for a string element in the Collection, I'm looking for other Collection elements. So I Dim a collection ("ciBitcoin") and use this:-

Code: Select all

For Each ciBitcoin In cBitcoin

Re: JSON files

Posted: Friday 15th September 2017 9:40am
by stevedee
Reading my last post again this morning, I realise something is not quite right with my explanation.

Although the Cars example appears to work, the variable "Make" should be an integer, not a string. The reason it appears to work as a string is that Gambas just quietly converts each integer into a string.

Even if you replace the integers in this example with booleans (True or False) the code still runs without error, but converts True to "T" and false to "".

Re: JSON files

Posted: Friday 15th September 2017 3:48pm
by cogier
Thanks for all the effort here. I can't get much from the Jornmo example. I tried the following
Public Sub Main()
Dim vNew As Variant
Dim sNew As String
Dim cCol, cCol1 As Collection

Shell "wget -O - https://poloniex.com/public?command=returnTicker" To sNew

vNew = Json.decode(sNew) ''Requires component 'gb.web'

cCol = vNew

For Each cCol1 In cCol
  GetCollectionData(cCol1)
Next

End 

Public Sub GetCollectionData(Col As Collection)
Dim v As Variant

For Each v In Col
  If v Is Collection Then ''Error here 'Wanted object got integer instead'
    GetCollectionData(v)
  Else
    Print "Key: " & Col.Key & " Value: " & v
  End If
Next

Catch
  Print "Key: " & Col.Key & " Value: " & v

End 
This got me: -
Key: id Value: 7
Key: id Value: 8
Key: id Value: 10
Key: id Value: 12
Key: id Value: 13
Key: id Value: 14
.......

Thanks for the explanation SteveDee
I discussed it with #3 son last night (he is doing Computer Science at Uni, but does not code in Gambas)
:o He'll need lots of these then "{}{}{}{}{}{}{}". ;)

Going to the pub now, I will get a friend to look at all this and see if he can add anything to this debate.