הערה
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות להיכנס או לשנות מדריכי כתובות.
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות לשנות מדריכי כתובות.
Question
Friday, December 4, 2015 3:34 PM
Hi
I am currently struggling to understand and deserialize some json returned from the following link:
it is a longish piece of data, so here is an extract showing the data I am trying to extract (channel_group: 'title' and 'id', and however many channel: data)
{
"channel_groups":
[
{
"publisher":
{
"key": "metabroadcast.com",
"name": "UK Channel Lineups",
"country": "ALL"
},
"title": "Scotland (Central)",
"available_countries":
[
"GB"
],
"channels":
[
{
"channel":
{
"publisher":
{
"key": "metabroadcast.com",
"name": "UK Channel Lineups",
"country": "ALL"
},
"title": "BBC One Scotland",
"image": "http://images.atlas.metabroadcast.com/pressassociation.com/channels/p131774.png",
"images":
[
{
"image_type": "logo",
"color": "color",
"theme": "light_transparent",
"width": 320,
"height": 180,
"aliases": [ ],
"v4_aliases": [ ],
"uri": "http://images.atlas.metabroadcast.com/pressassociation.com/channels/p2201211212.png"
},
{
"image_type": "logo",
"color": "color",
"theme": "light_opaque",
"width": 320,
"height": 180,
"aliases": [ ],
"v4_aliases": [ ],
"uri": "http://images.atlas.metabroadcast.com/pressassociation.com/channels/p131774.png"
},
{
"image_type": "logo",
"color": "color",
"theme": "dark_transparent",
"width": 320,
"height": 180,
"aliases": [ ],
"v4_aliases": [ ],
"uri": "http://images.atlas.metabroadcast.com/pressassociation.com/channels/p1201211212.png"
}
],
"media_type": "video",
"high_definition": false,
"regional": true,
"broadcaster":
{
"key": "bbc.co.uk",
"name": "BBC",
"country": "GB"
},
"available_from":
[
{
"key": "bbc.co.uk",
"name": "BBC",
"country": "GB"
},
{
"key": "pressassociation.com",
"name": "PA",
"country": "GB"
}
],
"parent":
{
"title": "BBC One",
"related_links": [ ],
"genres": [ ],
"aliases": [ ],
"v4_aliases": [ ],
"id": "cbPF"
},
"related_links":
[
{
"type": "simulcast",
"url": "http://www.bbc.co.uk/tv/bbcone/live"
}
],
"start_date": "1999-01-01T00:00:00Z",
"genres":
[
"http://pressassociation.com/genres/entertainment"
],
"aliases":
[
"bbcone-scotland",
"http://pressassociation.com/channels/2",
"http://xmltv.radiotimes.com/channels/101",
"http://youview.com/service/1129",
"http://atlas.metabroadcast.com/4.0/channels/hkq6"
],
"v4_aliases": [ ],
"uri": "http://www.bbc.co.uk/services/bbcone/scotland",
"id": "cbbv",
"type": "channel"
},
"channel_number": "101",
"start_date": "2014-03-25T00:00:00Z"
},
{"channel": { ....... etc for multiple 'channel'
and at the bottom of entire file:
"v4_aliases": [ ],
"uri": "http://ref.atlasapi.org/regions/pressassociation.com/4-123",
"id": "cbhJ",
"type": "region"
}
]
}
Here is a function I managed to get to work on some other data from same site:
Public Function GetProviders() As List(Of groups)
Dim p As New List(Of groups)
Dim src As String = "http://atlas.metabroadcast.com/3.0/channel_groups.json?type=platform"
Dim client As New Net.WebClient()
Dim stream As IO.Stream = client.OpenRead(src)
Dim reader As New IO.StreamReader(stream)
Dim jsonData As String = reader.ReadToEnd
reader.Close()
Dim allData As JObject = JObject.Parse(jsonData)
For Each token As JToken In allData("channel_groups")
Dim gr As New groups
Dim nr As New region
gr.groupname = token("title").ToString & " ( " & token("id").ToString & " )"
gr.groupID = token("id").ToString
Dim r As IList = CType(token("regions"), IList)
For Each i As JToken In r
gr.regions.Add(New region With {.regionID = i("id").ToString, .regionname = i("title").ToString & " ( " & i("id").ToString & " )"})
Next
p.Add(gr)
Next
Return p
End Function
I have tried all sorts of google searches etc and can not find any examples that seem to fit what I need. I am hoping there are some users here who can offer some assistance.
Regards Les, Livingston, Scotland
All replies (21)
Friday, December 4, 2015 6:21 PM ✅Answered | 2 votes
If you don't need the entire object hierarchy and just want to extract some particular values then you might start with code something like:
Option Strict On
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Imports System.Net.Http
Imports System.IO
Module Module1
Sub Main()
Dim t = JsonTestAsync()
Console.ReadKey()
End Sub
Private Async Function JsonTestAsync() As Task
Using client As New HttpClient
Dim response = Await client.GetAsync("https://atlas.metabroadcast.com/3.0/channel_groups/cbhJ.json?apiKey={insert your API key}&annotations=channels")
Using reader As New StreamReader(Await response.Content.ReadAsStreamAsync)
Using jsonreader = New JsonTextReader(reader)
Dim serializer = New JsonSerializer()
Dim document As JObject = CType(serializer.Deserialize(jsonreader), JObject)
For Each result In document
Console.WriteLine(result.Key)
For Each channelgroup In result.Value
Console.WriteLine("Title = " & channelgroup.Item("title").ToString)
Console.WriteLine("ID = " & channelgroup.Item("id").ToString)
For Each channel In channelgroup.Item("channels")
Dim first = channel.Children.First
Dim titleInfo = first.Children.First
Dim numberInfo = first.Next
Console.WriteLine(numberInfo.Children.First.ToString & " = " & titleInfo.Item("title").ToString)
Next
Next
Next
End Using
End Using
End Using
End Function
End Module
Depending on how much of the model you plan to consume, cherry picking values out of the stream may be quicker/easier than building the entire document model.
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
Friday, December 4, 2015 4:36 PM | 1 vote
Les,
Several months ago I posted this which uses NewtonSoft.JSON.
You might want to have a look and see if that'll help.
If I had eight hours to chop down a tree, I'd spend six sharpening my axe. -- Abraham Lincoln
Friday, December 4, 2015 4:59 PM
You have to make a custom object or objects with properties that match the properties of the JSON object. You may need to use a List(of T) in the parent object, since it looks like you have arrays in the JSON object.
I don't know what all the stream stuff is about, because the src has the JSON and that's all you need is the string variable.
https://www.youtube.com/watch?v=ly3ivuQUgB0
http://www.codeproject.com/Tips/79435/Deserialize-JSON-with-C
https://msdn.microsoft.com/en-us/library/dd293589.aspx?f=255&MSPPError=-2147217396
Friday, December 4, 2015 6:28 PM | 1 vote
Les,
Until I looked at Reed's post, I didn't realize that you have your API key in the URL.
I'd suggest that you remove that!
If I had eight hours to chop down a tree, I'd spend six sharpening my axe. -- Abraham Lincoln
Friday, December 4, 2015 6:28 PM
Hi
I have downloaded your code Frank, and will need to spend some time to digest it.
DA924 - the streaming is purely my way of fetching the data from the web site. The function I posted is very poor code as it is the result of much trial and error and just ended up that way. If I manage to get all the way through, I would clean everything up.
My overall objective: I fetch the data for Providers and extract a set of title/id/regions for each provider - populate 2 CB with those (done and working). A third CB would be populated with the channel data which is the data I am struggling with. I get the Provider/Region OK which provides title/id for the needed channels, but here is where I have hit the wall. If I manage to get the channel data then my next step would be to fetch the schedule data (yet another brick wall facing me:)
I can create class(es) as needed, but since I am trying to get partial data from the (well over 100 channels) I am well and truly stuck.
'You have to make a custom object or objects with properties that match the properties of the JSON object.'
That is one area that I am struggling with as I can't sort out how to 'isolate' the required data from the data I don't need from the JSON string.
Regards Les, Livingston, Scotland
Friday, December 4, 2015 6:32 PM
Les,
Until I looked at Reed's post, I didn't realize that you have your API key in the URL.
I'd suggest that you remove that!
If I had eight hours to chop down a tree, I'd spend six sharpening my axe. -- Abraham Lincoln
Thanks for the reminder - I wouldn't have been able to test the document structure without it, but I've edited the sample code to remove the API key.
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
Friday, December 4, 2015 6:55 PM
Hi
I have downloaded your code Frank, and will need to spend some time to digest it.
DA924 - the streaming is purely my way of fetching the data from the web site. The function I posted is very poor code as it is the result of much trial and error and just ended up that way. If I manage to get all the way through, I would clean everything up.
My overall objective: I fetch the data for Providers and extract a set of title/id/regions for each provider - populate 2 CB with those (done and working). A third CB would be populated with the channel data which is the data I am struggling with. I get the Provider/Region OK which provides title/id for the needed channels, but here is where I have hit the wall. If I manage to get the channel data then my next step would be to fetch the schedule data (yet another brick wall facing me:)
I can create class(es) as needed, but since I am trying to get partial data from the (well over 100 channels) I am well and truly stuck.
'You have to make a custom object or objects with properties that match the properties of the JSON object.'
That is one area that I am struggling with as I can't sort out how to 'isolate' the required data from the data I don't need from the JSON string.
Regards Les, Livingston, Scotland
Well, stop using the stream stuff. It's all there in the string variable.
Query the JSON string with Linq then and return a result of a anonymous objects with properties of data that you want -- project out and shape what you want a linq projection.
http://www.newtonsoft.com/json/help/html/QueryingLINQtoJSON.htm
Find out how to use Linq projection in VB using anonymous objects. I am tired of looking for VB stuff.
https://msdn.microsoft.com/en-us/library/bb384767.aspx
https://msdn.microsoft.com/en-us/library/bb763068.aspx
Friday, December 4, 2015 8:00 PM
Les,
Until I looked at Reed's post, I didn't realize that you have your API key in the URL.
I'd suggest that you remove that!
If I had eight hours to chop down a tree, I'd spend six sharpening my axe. -- Abraham Lincoln
Hi
Thanks Frank - key obscured
Regards Les, Livingston, Scotland
Friday, December 4, 2015 8:35 PM
If you don't need the entire object hierarchy and just want to extract some particular values then you might start with code something like:
Option Strict On Imports Newtonsoft.Json Imports Newtonsoft.Json.Linq Imports System.Net.Http Imports System.IO Module Module1 Sub Main() Dim t = JsonTestAsync() Console.ReadKey() End Sub Private Async Function JsonTestAsync() As Task Using client As New HttpClient Dim response = Await client.GetAsync("https://atlas.metabroadcast.com/3.0/channel_groups/cbhJ.json?apiKey={insert your API key}&annotations=channels") Using reader As New StreamReader(Await response.Content.ReadAsStreamAsync) Using jsonreader = New JsonTextReader(reader) Dim serializer = New JsonSerializer() Dim document As JObject = CType(serializer.Deserialize(jsonreader), JObject) For Each result In document Console.WriteLine(result.Key) For Each channelgroup In result.Value Console.WriteLine("Title = " & channelgroup.Item("title").ToString) Console.WriteLine("ID = " & channelgroup.Item("id").ToString) For Each channel In channelgroup.Item("channels") Dim first = channel.Children.First Dim titleInfo = first.Children.First Dim numberInfo = first.Next Console.WriteLine(numberInfo.Children.First.ToString & " = " & titleInfo.Item("title").ToString) Next Next Next End Using End Using End Using End Function End Module
Depending on how much of the model you plan to consume, cherry picking values out of the stream may be quicker/easier than building the entire document model.
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
Hi Reed
I missed your post until it was referred to further on.
I can't get your code to compile.
1. Imports System.Net.Http is not valid. Http - ERROR: namespace or type not found or no public members ........
2. Private Async Function JsonTestAsync() As Task - ERROR:
lacks an 'await' operator so will run syncronously ......
3. Using client As New HttpClient - ERROR: Type HttpClient not defined .....
Regards Les, Livingston, Scotland
Friday, December 4, 2015 8:41 PM
Hi
I have downloaded your code Frank, and will need to spend some time to digest it.
DA924 - the streaming is purely my way of fetching the data from the web site. The function I posted is very poor code as it is the result of much trial and error and just ended up that way. If I manage to get all the way through, I would clean everything up.
My overall objective: I fetch the data for Providers and extract a set of title/id/regions for each provider - populate 2 CB with those (done and working). A third CB would be populated with the channel data which is the data I am struggling with. I get the Provider/Region OK which provides title/id for the needed channels, but here is where I have hit the wall. If I manage to get the channel data then my next step would be to fetch the schedule data (yet another brick wall facing me:)
I can create class(es) as needed, but since I am trying to get partial data from the (well over 100 channels) I am well and truly stuck.
'You have to make a custom object or objects with properties that match the properties of the JSON object.'
That is one area that I am struggling with as I can't sort out how to 'isolate' the required data from the data I don't need from the JSON string.
Regards Les, Livingston, Scotland
Well, stop using the stream stuff. It's all there in the string variable.
Query the JSON string with Linq then and return a result of a anonymous objects with properties of data that you want -- project out and shape what you want a linq projection.
http://www.newtonsoft.com/json/help/html/QueryingLINQtoJSON.htm
Find out how to use Linq projection in VB using anonymous objects. I am tired of looking for VB stuff.
Well, you have me lost (easily done). I need to fetch the data somehow! The 'src' variable is just the web address.
Regards Les, Livingston, Scotland
Friday, December 4, 2015 9:05 PM
Hi
I have downloaded your code Frank, and will need to spend some time to digest it.
DA924 - the streaming is purely my way of fetching the data from the web site. The function I posted is very poor code as it is the result of much trial and error and just ended up that way. If I manage to get all the way through, I would clean everything up.
My overall objective: I fetch the data for Providers and extract a set of title/id/regions for each provider - populate 2 CB with those (done and working). A third CB would be populated with the channel data which is the data I am struggling with. I get the Provider/Region OK which provides title/id for the needed channels, but here is where I have hit the wall. If I manage to get the channel data then my next step would be to fetch the schedule data (yet another brick wall facing me:)
I can create class(es) as needed, but since I am trying to get partial data from the (well over 100 channels) I am well and truly stuck.
'You have to make a custom object or objects with properties that match the properties of the JSON object.'
That is one area that I am struggling with as I can't sort out how to 'isolate' the required data from the data I don't need from the JSON string.
Regards Les, Livingston, Scotland
Well, stop using the stream stuff. It's all there in the string variable.
Query the JSON string with Linq then and return a result of a anonymous objects with properties of data that you want -- project out and shape what you want a linq projection.
http://www.newtonsoft.com/json/help/html/QueryingLINQtoJSON.htm
Find out how to use Linq projection in VB using anonymous objects. I am tired of looking for VB stuff.
https://msdn.microsoft.com/en-us/library/bb384767.aspx
https://msdn.microsoft.com/en-us/library/bb763068.aspx
Well, you have me lost (easily done). I need to fetch the data somehow! The 'src' variable is just the web address.
Regards Les, Livingston, Scotland
JSON is string regardless of whatever variable it would up in just query it with Linq. It is simple.
Friday, December 4, 2015 9:08 PM
JSON is string regardless of whatever variable it would up in just query it with Linq. It is simple.
Hi
No, I am unsure of what you mean. I do actually need to fetch the data, it won't come to me by magic.
Regards Les, Livingston, Scotland
Friday, December 4, 2015 9:17 PM
This is really all you needed to do to get the JSON into a string variable. Then it would a simple task to query the data in the string variable using Linq-2-JSON and using a LINQ projection.
http://www.newtonsoft.com/json/help/html/linqtojson.htm
You want to go the hard way to the moon and back on something so simple.
Friday, December 4, 2015 9:20 PM
I will say that most of this stuff with examples an all are really easy to fine that in C#, but not VB.NET. But you can see the example in C# and see how easy it is and write it in VB,NET
Friday, December 4, 2015 9:27 PM
Les,
Did you know that you can also get an XML version of that? To do that, in your actual full url, you'll see "=json" ... change that to "=xml".
I say that because looking at the XML, the structure is more obvious (or it is to me anyway).
*****
I see the id that you asked for but I don't see "title" and I'm not sure what you mean about "data" either, but this might get you started - using XML. You can then later work out the JSON using the Newton assembly but you first need to work out just what you want.
In a new project, give this a go as a start then examine the XML returned when it gets to "Stop" below:
Option Strict On
Option Explicit On
Option Infer Off
Imports <xmlns:play="http://ref.atlasapi.org/">
Public Class Form1
Private Sub Form1_Load(sender As System.Object, _
e As System.EventArgs) _
Handles MyBase.Load
Const url As String = "xml_URL_Here"
Dim xDoc As XElement = XElement.Load(url)
For Each group As XElement In xDoc...<play:channel_group>
Dim id As String = group...<id>.Value
Stop
Next
Stop
End Sub
End Class
If I had eight hours to chop down a tree, I'd spend six sharpening my axe. -- Abraham Lincoln
Friday, December 4, 2015 9:34 PM
Hi Les,
System.Net.Http is in framework 4.5+ so I have to assume you are targeting an earlier version of the framework. Error's 2 and 3 are the result of 1.
If you can move to Visual Studio 2015 then you can use the sample as-is. Otherwise you'll need to factor out the HttpClient and use a System.Net.HttpWebRequest instead (or other means of downloading the data into a string).
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
Friday, December 4, 2015 9:42 PM | 2 votes
Les (yes, I know I'm replying to Reed, but this is a follow-up),
If you want to try Reed's method - and I would encourage you to because it'll be a LOT faster than XML - then instead of "downloading" it, per se, you can get the string (all of it):
Imports System.IO
Imports System.Net
Private Function ReturnTextFromURL(ByVal url As String) As String
Dim retVal As String = ""
Try
Dim request As WebRequest = WebRequest.Create(url)
Using response As HttpWebResponse = DirectCast(request.GetResponse, HttpWebResponse)
Using dataStream As Stream = response.GetResponseStream
Using reader As New StreamReader(dataStream)
Dim responseFromServer As String = reader.ReadToEnd()
retVal = responseFromServer
End Using
End Using
End Using
Catch ex As Exception
retVal = ""
End Try
Return retVal
End Function
If I had eight hours to chop down a tree, I'd spend six sharpening my axe. -- Abraham Lincoln
Saturday, December 5, 2015 12:11 AM
Hi Les,
System.Net.Http is in framework 4.5+ so I have to assume you are targeting an earlier version of the framework. Error's 2 and 3 are the result of 1.
If you can move to Visual Studio 2015 then you can use the sample as-is. Otherwise you'll need to factor out the HttpClient and use a System.Net.HttpWebRequest instead (or other means of downloading the data into a string).
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"
Hi Reed
Yes, I am using Net 4.5.1on windows 8.1 with VB 2013
I can get the string OK, but right now, I don't have enough time to delve too deeply. Things might ease a little tomorrow. I will try it out though.
Regards Les, Livingston, Scotland
Saturday, December 5, 2015 3:12 PM
Hi one and all
I have made some progress, thanks to contributions here. This is the code so far which lets me choose a Provider and Region, and from those, get the appropriate channels. Now, I will need to deal with getting the EPG data for user selected channels. (maybe DA924 will approve of my using Franks code to fetch the data)
Code so far
Option Strict On
Option Explicit On
Option Infer Off
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Imports System.Net
Imports System.IO
Module GetData
Public providers As New List(Of groups)
Public Function GetProviders() As List(Of groups)
' provides the data to populate CB1 and CB2
Dim p As New List(Of groups)
Dim src As String = ReturnTextFromURL("http://atlas.metabroadcast.com/3.0/channel_groups.json?type=platform")
Dim allData As JObject = JObject.Parse(src)
For Each token As JToken In allData("channel_groups")
Dim gr As New groups
Dim nr As New region
gr.groupname = token("title").ToString & " ( " & token("id").ToString & " )"
gr.groupID = token("id").ToString
Dim r As IList = CType(token("regions"), IList)
For Each i As JToken In r
gr.regions.Add(New region With {.regionID = i("id").ToString, .regionname = i("title").ToString & " ( " & i("id").ToString & " )"})
Next
p.Add(gr)
Next
Return p
End Function
Public Function FetchChannels(region As String) As List(Of channel)
' provides Channel List for DGV based on Provider and Region
' in CB1 and CB2 thanks to Frank and Reed
Dim Channels As New List(Of channel)
Dim response As String = ReturnTextFromURL("https://atlas.metabroadcast.com/3.0/channel_groups/" & region & ".json?apiKey=[API KEY]&annotations=channels")
Dim alldata As JObject = JObject.Parse(response)
For Each result As KeyValuePair(Of String, JToken) In alldata
For Each channelgroup As JToken In result.Value
For Each channel As JToken In channelgroup.Item("channels")
Dim chdata As JToken = channel.Children.First.Children.First
Dim logo As String = Nothing
Try
logo = chdata.Item("image").ToString()
Catch ex As Exception
logo = Nothing
End Try
Dim ch As New channel With {.ID = chdata.Item("id").ToString, .Name = chdata.Item("title").ToString, .Chan = channel.Item("channel_number").ToString, .logo = logo}
Channels.Add(ch)
Next
Next
Next
Return Channels
End Function
Private Function ReturnTextFromURL(ByVal url As String) As String
' provides JSON string to ther functions thanks Frank
Dim retVal As String = Nothing
Try
Dim request As WebRequest = WebRequest.Create(url)
Using response As HttpWebResponse = DirectCast(request.GetResponse, HttpWebResponse)
Using dataStream As Stream = response.GetResponseStream
Using reader As New StreamReader(dataStream)
Dim responseFromServer As String = reader.ReadToEnd()
retVal = responseFromServer
End Using
End Using
End Using
Catch ex As Exception
retVal = Nothing
End Try
Return retVal
End Function
End Module
Class groups
Property groupname As String
Property groupID As String
Property regions As New List(Of region)
End Class
Class region
Property regionID As String
Property regionname As String
End Class
Class channel
Property USE As Boolean = False
Property Chan As String = Nothing
Property ID As String = Nothing
Property Name As String = Nothing
Property logo As String = Nothing
End Class
Regards Les, Livingston, Scotland
Monday, December 7, 2015 6:21 PM
If it works for go with it, since I am posting from a hospital bed as I will tore up my knee this past Friday.
Wednesday, December 9, 2015 10:03 PM
So, I've been playing with this some more and have come up with something which I like much better than Newtonsoft.JSON for dealing with JSON documents when you don't exactly know the document model. I've created a thread about it here.
I've come to see how you could use LINQ to get anonymous objects representing the document model using Newtonsoft.JSON, but it can still be tricky to figure out the document model in the first place so that you can construct an accurate LINQ statement.
I've tried the code in that other thread against your data source (sorry, I'll stop using your API key now! lol) and it works very well. The resulting object model is easy to understand and work with. I would encourage you to try that code with this JSON data.
Reed Kimble - "When you do things right, people won't be sure you've done anything at all"