How can i bind xml to mvvm wpf? - c#

I have a problem. I have wpf mvvm app and I need to bind xml, but I don't know how.
I have there elements model, elements vm, and a view. Everything work, but all of that elements have "some base" model.
class ItemModel
{
public ItemModel(string name, double weight, double sg, double volume)
{
Name = name;
Weight = weight;
Sg = sg;
Volume = volume;
}
public string Name { get; set; }
public double Weight { get; set; }
public double Sg { get; set; }
public double Volume { get; set; }
}
This is my VM.
class ItemViewModel : BaseVM
{
public ItemViewModel(string name, double sg, double weight, double volume)
{
Name = name;
Weight = weight;
Sg = sg;
Volume = volume;
}
public string Name { get; set; }
private double _weight;
public double Weight
{
get => _weight;
set
{
_weight = value;
RaisePropertyChanged();
}
}
private double _sg;
public double Sg
{
get => _sg;
set
{
_sg = value;
Weight = value * _volume;
RaisePropertyChanged("Weight");
RaisePropertyChanged("Sg");
}
}
private double _volume;
public double Volume
{
get => _volume;
set
{
_volume = value;
_weight = value * _sg;
RaisePropertyChanged();
RaisePropertyChanged("Weight");
RaisePropertyChanged("Sg");
}
}
}
This is my MainVM
class MainViewModel
{
private DataModel Data;
public ObservableCollection<ItemViewModel> Items { get; set; }
public ListCollectionView FilteredItems { get; set; }
public MainViewModel()
{
Data = new DataModel();
Items = new ObservableCollection<ItemViewModel>();
FilteredItems = new ListCollectionView(Items)
{
Filter = item => ((ItemViewModel)item).Volume != 0,
IsLiveFiltering = true,
LiveFilteringProperties =
{
nameof (ItemViewModel.Volume)
}
};
Load();
}
public void Load()
{
foreach (var item in Data.GetItems())
Items.Add(new ItemViewModel(item.Name, item.Weight, item.Sg, item.Volume));
}
}
I have some "DataModel"
class DataModel
{
public List<ItemModel> GetItems() =>
new List<ItemModel>
{
new ItemModel("Water", 0.00, 1.025, 0.00),
new ItemModel("Ballast", 0.00, 1.000, 0.00),
new ItemModel("Oil", 0.00, 1.040, 0.00),
};
}
And this is xml i want to bind instead.
<ballast>
<tank ID="FPTW" Name="Forepeak" Weight="0.00" SG="1.025" Volume="0.00"> </tank>
</ballast>
Please help me how can i bind this xml file instead list in DataModel.

I strongly recommend to deserialize your XML to "real" objects. In your example you want to have a list of tanks in your programm. The view (XAML) should not know if the "data storage" is a xml file, database or whatever. Just bind to a list of TankViewModel (or in your case you named it ItemViewModel. Hopefully you don't blow something up with all these tanks....
This is how you deserialize the xml to "real" objects (full working console app:
https://dotnetfiddle.net/zCHSmc
using System;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
MainViewModel vm = new MainViewModel();
foreach(tank t in vm.ListOfTanks.ballast)
{
Console.WriteLine(t.ID);
}
}
public class MainViewModel
{
public tanks ListOfTanks
{
get
{
string xmlContent = "<?xml version=\"1.0\" encoding=\"utf-16\"?><tanks xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"> <ballast><tank><ID>ksj</ID></tank> </ballast></tanks>";
tanks allTanks = null;
XmlSerializer serializer = new XmlSerializer(typeof(tanks));
//if you have a xml file you can use serializer.Deserialize("yourFile.xml"); instead of the "in memory stream"
using (TextReader reader = new StringReader(xmlContent))
{
allTanks =(tanks)serializer.Deserialize(reader);
}
return allTanks;
}
}
}
public class tanks
{
public tanks()
{
ballast = new List<tank>();
}
public List<tank> ballast {get;set;}
}
public class tank
{
public string ID {get;set;}
}
}

Related

How do I Make Reusable Class for Inventory/Item System? C#

I want to make a class that I can use to make endless items and put them in a list, for my inventory system. I don't know a lot of C# so if there is an entirely different solution, I would be open to hearing it.
Here is what I tried.
using System;
using System.Collections.Generic;
namespace Game
{
public class Item
{
bool isChestArmor, isLegArmor, isOneHanded, isItem, isWeapon, hpItem, manaItem, onlyOffHand;
double damage, resistance, cost;
string name;
public string Name
{
get {return name;}
set {name = value;}
}
public double Damage
{
get {return damage;}
set {damage = value;}
}
public double Resistance
{
get {return resistance;}
set {resistance = value;}
}
public double Cost
{
get {return cost;}
set {cost = value;}
}
public bool IsChestArmor
{
get {return isChestArmor;}
set {isChestArmor = value;}
}
public bool IsLegArmor
{
get {return isLegArmor;}
set {isLegArmor = value;}
}
public bool IsItem
{
get {return isItem;}
set {isItem = value;}
}
public bool IsWeapon
{
get {return isWeapon;}
set {isWeapon = value;}
}
public bool IsOneHanded
{
get {return isOneHanded;}
set {isOneHanded = value;}
}
public bool OnlyOffHand
{
get {return onlyOffHand;}
set {onlyOffHand = value;}
}
public bool HpItem
{
get {return hpItem;}
set {hpItem = value;}
}
public bool ManaItem
{
get {return manaItem;}
set {manaItem = value;}
}
}
class MainClass
{
public static void Main()
{
Item I = new Item();
List<Item> Inventory = new List<Item>();
I.ManaItem = false;
I.HpItem = false;
I.OnlyOffHand = false;
I.IsChestArmor = false;
I.IsLegArmor = false;
I.IsWeapon = true;
I.Damage = 10;
I.Cost = 75;
I.Resistance = 0;
I.Name = "Short Sword";
Inventory.Add(I);
Console.WriteLine(Inventory[0].Name);
Console.ReadLine();
}
}
}
This doesn't work because I would need a new class for every iteration of an item. It would be nice if there was a way to make duplicates of the Item class, and I'm sure there is a way to do this, I just simply don't know how.
Thank you.
Based on your comments, I think this is the core learning you're looking for in the question.
This problem calls for an understanding of polymorphism, or the representation of related concepts in an inheritance hierarchy. Here's one way you can approach that in C#.
(Update to original answer: Added DancingSword that can act like a weapon and like armor).
namespace Game
{
public enum ArmorLocation
{
All, Head, Chest, Leg, Foot
}
public interface IItem
{
string Name { get; set; }
}
public interface IWeapon : IItem
{
double Damage { get; set; }
}
public interface IArmor : IItem
{
double Resistance { get; set; }
ArmorLocation Location { get; set; }
}
public class Weapon : IWeapon
{
public double Damage { get; set; }
public string Name { get; set; }
}
public class DancingSword : IWeapon, IArmor
{
public double Damage { get; set; }
public string Name { get; set; }
public double Resistance { get; set; }
public ArmorLocation Location { get; set; }
}
public class Armor : IArmor
{
public double Resistance { get; set; }
public ArmorLocation Location { get; set; }
public string Name { get; set; }
}
class MainClass
{
public static void Main()
{
var Inventory = new List<IItem>();
Inventory.Add(new Weapon() { Name = "Shortsword", Damage = 10.0 });
Inventory.Add(new Armor() { Name = "Steel Helm", Location = ArmorLocation.Head, Resistance = 3.0 });
Inventory.Add(new Armor() { Name = "Skeeverhide Boots", Location = ArmorLocation.Foot, Resistance = 1.0 });
Inventory.Add(new DancingSword() { Name = "Dancing Sword +1", Damage = 8.0, Location = ArmorLocation.All, Resistance = 1.0 });
Console.WriteLine("Weapon items:");
foreach (var item in Inventory.OfType<IWeapon>())
Console.WriteLine(item.Name);
Console.WriteLine("Armor items:");
foreach (var item in Inventory.OfType<IArmor>())
Console.WriteLine(item.Name);
Console.ReadLine();
}
}
}

Sort MultiLevel Data with Linq

I have a data structure as follows:
public class BranchLevel_1
{
public string Name { get; set; }
public ObservableCollection<BranchLevel_2> Children { get; set; }
public BranchLevel_1(string name, List<BranchLevel_2> children)
{
this.Name = name;
this.Children = new ObservableCollection<BranchLevel_2>(children);
}
}
public class BranchLevel_2
{
public ObservableCollection<BranchLevel_3> Contents { get; set; }
public BranchLevel_2(List<string> contents)
{
this.Contents = new ObservableCollection<BranchLevel_3>();
for (int i = 0; i < contents.Count; i++)
{
this.Contents.Add(new BranchLevel_3(contents[i]));
}
}
}
public class BranchLevel_3
{
public string Content { get; set; }
public BranchLevel_3(string text)
{
this.Content = text;
}
}
Sorting data on the first level is easy and I can obtain in easily by:
Level1_Data.OrderBy(item => item.Name).ToList()
However, I am stuck with sorting on the second level. BranchLevel_2 class is just a container for items stored in BranchLevel_3 classes. Therefore I would like to sort Level2 with data stored in BranchLevel_2.Contents1.Content value. This syntax for me seems to be correct and I cannot locate the problem...
Level1_Data.Select(item_Level1 => item_Level1.Children.OrderBy(item_Level2 => item_Level2.Contents[1].Content)).ToList();
Any hints?
Here is the rusult (indicated in yellow is supposed to be sorted alphabetically)
Why not just sort the contents before adding them to the ObservableCollection
public class BranchLevel_2
{
public ObservableCollection<BranchLevel_3> Contents { get; set; }
public BranchLevel_2(List<string> contents)
{
this.Contents = new ObservableCollection<BranchLevel_3>();
foreach (var content in contents.OrderBy(c => c))
{
this.Contents.Add(new BranchLevel_3(content));
}
}
}
Here is a solution that solved the problem, thanks to suggestion from #bhmahler
public class BranchLevel_1
{
public string Name { get; set; }
public ObservableCollection<BranchLevel_2> Children { get; set; }
public BranchLevel_1(string name, List<BranchLevel_2> children)
{
this.Name = name;
//this line needs to be added before creating ObservableCollection
children.OrderBy(item_level2 => item_level2.Contents[1].Content).ToList();
this.Children = new ObservableCollection<BranchLevel_2>(children);
}
}

How to deserialize a Json object with an Android app

I'm trying to deserialize a JSon object with an Anroid app, but can't get it running. The intention is to read data from an asset item ("AllPoloniexPairs.txt"), which is the JSON objrct I'm trying to deserialyze and get "currencyPairs" from the Data part and put it into the spinner.
Below is (part of) my JSON
{"BTC_BCN":{"id":7,"baseID":28,"quoteID":17,"base":"BTC","quote":"BCN","currencyPair":"BTC_BCN"},"BTC_BTS":{"id":14,"baseID":28,"quoteID":32,"base":"BTC","quote":"BTS","currencyPair":"BTC_BTS"}}
This is my code
public class Data
{
public int id { get; set; }
public int baseID { get; set; }
public int quoteID { get; set; }
public string Base { get; set; }
public string Quote { get; set; }
public string currencyPair { get; set; }
}
public class Pairs
{
public string id { get; set; }
public Data data { get; set; }
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
using (StreamReader sr = new StreamReader(assets.Open("AllPoloniexPairs.txt")))
{
content = sr.ReadToEnd();
}
Pairs pairs = JsonConvert.DeserializeObject<Pairs>(content);
ArrayAdapter<String> adapter;
Spinner spinner2 = (Spinner)FindViewById(Resource.Id.spinner2);
List<string> spinnerItems = new List<string>();
foreach (var k in pairs.data.currencyPair)
{
spinnerItems.Add(k.ToString());
}
spinnerItems.Sort();
adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleSpinnerDropDownItem, spinnerItems);
spinner2.Adapter = adapter;
}
When I skip the foreach loop the app runs, but of course with no items in the spinner. If I include the foreach part, the application hangs.
I have tried several things now for the last couple of hours, but without any luck.
What could be the reason that the code doesn't run?
Well why do you reinvent the wheel google has already done it for you you can do it in two lines of code:
https://github.com/google/gson
Gson gson = new Gson();
MyClass myClass= gson.fromJson(json, MyClass.class);
Well sorry for the delay was figuring your json data and it seems wrong to me and GSON you better use something like :
[
{
"id": 7,
"baseID": 28,
"quoteID": 17,
"base": "BTC",
"quote": "BCN",
"currencyPair": "BTC_BCN"
},
{
"id": 14,
"baseID": 28,
"quoteID": 32,
"base": "BTC",
"quote": "BTS",
"currencyPair": "BTC_BTS"
}
]
You were using an object which has two objects in it.
That's not an array remember array should have brackets.
Now let's do this with the above json we have a class called MyClass let's say:
public class MyClass {
int id;
int baseID;
int quoteID;
String base;
String quote;
String currencyPair;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getBaseID() {
return baseID;
}
public void setBaseID(int baseID) {
this.baseID = baseID;
}
public int getQuoteID() {
return quoteID;
}
public void setQuoteID(int quoteID) {
this.quoteID = quoteID;
}
public MyClass(String currencyPair) {
this.currencyPair = currencyPair;
}
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
public String getQuote() {
return quote;
}
public void setQuote(String quote) {
this.quote = quote;
}
}
Now in your activity use:
Gson gson = new Gson();
String jsonOutput = "[{\"id\":7,\"baseID\":28,\"quoteID\":17,\"base\":\"BTC\",\"quote\":\"BCN\",\"currencyPair\":\"BTC_BCN\"},{\"id\":14,\"baseID\":28,\"quoteID\":32,\"base\":\"BTC\",\"quote\":\"BTS\",\"currencyPair\":\"BTC_BTS\"}]";
MyClass[] posts = gson.fromJson(jsonOutput, MyClass[].class);
Log.v("SteveMoretz", String.valueOf(posts.length));
You will get 2 by the Log which means you have two objects now you can use where ever you want.:)

Get Distinct List of Values from Nested Object

I am deserializing an XML file to and object model. Although this is not the actual model, below is similar in structure to what I have.
[Serializable()]
[System.Xml.Serialization.XmlRoot("AutoEnvelope")]
public class AutoBody
{
[XmlArray("AutoBody")]
[XmlArrayItem("Vehicles", typeof(Vehicles))]
public Vehicles[] Vehicles { get; set; }
}
[Serializable()]
public class Vehicles
{
[XmlElement("SelectedCar", typeof(SelectedCar))]
public SelectedCar SelectedCar { get; set; }
[XmlElement("OfferedVehicles", typeof(OfferedVehicles))]
public OfferedVehicles OfferedVehicles { get; set; }
}
[Serializable()]
public class SelectedCar
{
[System.Xml.Serialization.XmlElement("Model")]
public string Model { get; set; }
[System.Xml.Serialization.XmlElement("NumTires")]
public int NumTires { get; set; }
[System.Xml.Serialization.XmlElement("Color")]
public string Color { get; set; }
}
I am trying to get a distinct list of SelectedCar.Color values and have been unsuccessful. Let's assume that I am storing the data in a variable called autoBody, I have tried variations of the following:
List<char> uniqueColors = autoBody.SelectMany(auto => auto.SelectedCar.Color).Distinct().ToList();
I am clearly doing something wrong, but am not clear on how to achieve what I am looking for.
The SelectMany() method is meant for projection multiple arrays (actually anything that implements IEnumerable<T>) into a single array.
For example, if you were having a list of AutoBody items and you wanted to accumulate all of their associated Vehicles into a single array, you would do:
IEnumerable<Vehicles> vehicles = autoBodies.SelectMany(x => x.Vehicles);
But, when you're using SelectMany on a string property (Color in your case), you're basically projecting the string into an IEnumerable<char> (since String does implement IEnumerable<char> because it's actually a sequence of characters).
Try using Select() instead:
List<string> uniqueColors = autoBody.Select(auto => auto.SelectedCar.Color)
.Distinct()
.ToList()
See MSDN
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication70
{
class Program
{
static void Main(string[] args)
{
AutoBody bodies = new AutoBody()
{
vehicles = new List<Vehicles>()
{
new Vehicles() {
SelectedCar = new SelectedCar() { Model = "Ford", NumTires = 1, Color = "red"}
},
new Vehicles() {
SelectedCar = new SelectedCar() { Model = "Chevy", NumTires = 2, Color = "blue"}
},
new Vehicles() {
SelectedCar = new SelectedCar() { Model = "Jeep", NumTires = 3, Color = "green"}
},
new Vehicles() {
SelectedCar = new SelectedCar() { Model = "Merecedes", NumTires = 4, Color = "red"}
},
}
};
List<string> colors = bodies.vehicles.Select(x => x.SelectedCar).Select(y => y.Color).Distinct().ToList();
}
}
[Serializable()]
[System.Xml.Serialization.XmlRoot("AutoEnvelope")]
public class AutoBody
{
[XmlArray("AutoBody")]
[XmlArrayItem("Vehicles", typeof(Vehicles))]
public List<Vehicles> vehicles { get; set; }
}
[Serializable()]
public class Vehicles
{
[XmlElement("SelectedCar", typeof(SelectedCar))]
public SelectedCar SelectedCar { get; set; }
//[XmlElement("OfferedVehicles", typeof(OfferedVehicles))]
//public OfferedVehicles OfferedVehicles { get; set; }
}
[Serializable()]
public class SelectedCar
{
[System.Xml.Serialization.XmlElement("Model")]
public string Model { get; set; }
[System.Xml.Serialization.XmlElement("NumTires")]
public int NumTires { get; set; }
[System.Xml.Serialization.XmlElement("Color")]
public string Color { get; set; }
}
}

Parse JSON in C#

I'm trying to parse some JSON data from the Google AJAX Search API. I have this URL and I'd like to break it down so that the results are displayed. I've currently written this code, but I'm pretty lost in regards of what to do next, although there are a number of examples out there with simplified JSON strings.
Being new to C# and .NET in general I've struggled to get a genuine text output for my ASP.NET page so I've been recommended to give JSON.NET a try. Could anyone point me in the right direction to just simply writing some code that'll take in JSON from the Google AJAX Search API and print it out to the screen?
EDIT: ALL FIXED! All results are working fine. Thank you again Dreas Grech!
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.ServiceModel.Web;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Text;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
GoogleSearchResults g1 = new GoogleSearchResults();
const string json = #"{""responseData"": {""results"":[{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://www.cheese.com/"",""url"":""http://www.cheese.com/"",""visibleUrl"":""www.cheese.com"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:bkg1gwNt8u4J:www.cheese.com"",""title"":""\u003cb\u003eCHEESE\u003c/b\u003e.COM - All about \u003cb\u003echeese\u003c/b\u003e!."",""titleNoFormatting"":""CHEESE.COM - All about cheese!."",""content"":""\u003cb\u003eCheese\u003c/b\u003e - everything you want to know about it. Search \u003cb\u003echeese\u003c/b\u003e by name, by types of milk, by textures and by countries.""},{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://en.wikipedia.org/wiki/Cheese"",""url"":""http://en.wikipedia.org/wiki/Cheese"",""visibleUrl"":""en.wikipedia.org"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:n9icdgMlCXIJ:en.wikipedia.org"",""title"":""\u003cb\u003eCheese\u003c/b\u003e - Wikipedia, the free encyclopedia"",""titleNoFormatting"":""Cheese - Wikipedia, the free encyclopedia"",""content"":""\u003cb\u003eCheese\u003c/b\u003e is a food consisting of proteins and fat from milk, usually the milk of cows, buffalo, goats, or sheep. It is produced by coagulation of the milk \u003cb\u003e...\u003c/b\u003e""},{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://www.ilovecheese.com/"",""url"":""http://www.ilovecheese.com/"",""visibleUrl"":""www.ilovecheese.com"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:GBhRR8ytMhQJ:www.ilovecheese.com"",""title"":""I Love \u003cb\u003eCheese\u003c/b\u003e!, Homepage"",""titleNoFormatting"":""I Love Cheese!, Homepage"",""content"":""The American Dairy Association\u0026#39;s official site includes recipes and information on nutrition and storage of \u003cb\u003echeese\u003c/b\u003e.""},{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://www.gnome.org/projects/cheese/"",""url"":""http://www.gnome.org/projects/cheese/"",""visibleUrl"":""www.gnome.org"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:jvfWnVcSFeQJ:www.gnome.org"",""title"":""\u003cb\u003eCheese\u003c/b\u003e"",""titleNoFormatting"":""Cheese"",""content"":""\u003cb\u003eCheese\u003c/b\u003e uses your webcam to take photos and videos, applies fancy special effects and lets you share the fun with others. It was written as part of Google\u0026#39;s \u003cb\u003e...\u003c/b\u003e""}],""cursor"":{""pages"":[{""start"":""0"",""label"":1},{""start"":""4"",""label"":2},{""start"":""8"",""label"":3},{""start"":""12"",""label"":4},{""start"":""16"",""label"":5},{""start"":""20"",""label"":6},{""start"":""24"",""label"":7},{""start"":""28"",""label"":8}],""estimatedResultCount"":""14400000"",""currentPageIndex"":0,""moreResultsUrl"":""http://www.google.com/search?oe\u003dutf8\u0026ie\u003dutf8\u0026source\u003duds\u0026start\u003d0\u0026hl\u003den-GB\u0026q\u003dcheese""}}, ""responseDetails"": null, ""responseStatus"": 200}";
g1 = JSONHelper.Deserialise<GoogleSearchResults>(json);
Response.Write(g1.content);
}
}
public class JSONHelper
{
public static T Deserialise<T>(string json)
{
T obj = Activator.CreateInstance<T>();
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
DataContractJsonSerializer serialiser = new DataContractJsonSerializer(obj.GetType());
ms.Close();
return obj;
}
}
/// Deserialise from JSON
[Serializable]
public class GoogleSearchResults
{
public GoogleSearchResults() { }
public GoogleSearchResults(string _unescapedUrl, string _url, string _visibleUrl, string _cacheUrl, string _title, string _titleNoFormatting, string _content)
{
this.unescapedUrl = _unescapedUrl;
this.url = _url;
this.visibleUrl = _visibleUrl;
this.cacheUrl = _cacheUrl;
this.title = _title;
this.titleNoFormatting = _titleNoFormatting;
this.content = _content;
}
string _unescapedUrl;
string _url;
string _visibleUrl;
string _cacheUrl;
string _title;
string _titleNoFormatting;
string _content;
[DataMember]
public string unescapedUrl
{
get { return _unescapedUrl; }
set { _unescapedUrl = value; }
}
[DataMember]
public string url
{
get { return _url; }
set { _url = value; }
}
[DataMember]
public string visibleUrl
{
get { return _visibleUrl; }
set { _visibleUrl = value; }
}
[DataMember]
public string cacheUrl
{
get { return _cacheUrl; }
set { _cacheUrl = value; }
}
[DataMember]
public string title
{
get { return _title; }
set { _title = value; }
}
[DataMember]
public string titleNoFormatting
{
get { return _titleNoFormatting; }
set { _titleNoFormatting = value; }
}
[DataMember]
public string content
{
get { return _content; }
set { _content = value; }
}
}
The code currently compiles and runs perfectly, but isn't returning any results. Could someone help me with returning what I require, the results ready to print out to the screen?
Edit:
Json.NET works using the same JSON and classes as the example above.
GoogleSearchResults g1 = JsonConvert.DeserializeObject<GoogleSearchResults>(json);
Link: Serializing and Deserializing JSON with Json.NET
Related
C# - parsing json formatted data into nested hashtables
Parse JSON array
[Update]
I've just realized why you weren't receiving results back... you have a missing line in your Deserialize method. You were forgetting to assign the results to your obj :
public static T Deserialize<T>(string json)
{
using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
return (T)serializer.ReadObject(ms);
}
}
Also, just for reference, here is the Serialize method :
public static string Serialize<T>(T obj)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
return Encoding.Default.GetString(ms.ToArray());
}
}
Edit
If you want to use Json.NET here are the equivalent Serialize/Deserialize methods to the code above..
Deserialize:
JsonConvert.DeserializeObject<T>(string json);
Serialize:
JsonConvert.SerializeObject(object o);
This are already part of Json.NET so you can just call them on the JsonConvert class.
Link: Serializing and Deserializing JSON with Json.NET
Now, the reason you're getting a StackOverflow is because of your Properties.
Take for example this one :
[DataMember]
public string unescapedUrl
{
get { return unescapedUrl; } // <= this line is causing a Stack Overflow
set { this.unescapedUrl = value; }
}
Notice that in the getter, you are returning the actual property (ie the property's getter is calling itself over and over again), and thus you are creating an infinite recursion.
Properties (in 2.0) should be defined like such :
string _unescapedUrl; // <= private field
[DataMember]
public string unescapedUrl
{
get { return _unescapedUrl; }
set { _unescapedUrl = value; }
}
You have a private field and then you return the value of that field in the getter, and set the value of that field in the setter.
Btw, if you're using the 3.5 Framework, you can just do this and avoid the backing fields, and let the compiler take care of that :
public string unescapedUrl { get; set;}
I found this approach which parse JSON into a dynamic object, it extends a DynamicObject and JavascriptConverter to turn the string into an object.
DynamicJsonObject
public class DynamicJsonObject : DynamicObject
{
private IDictionary<string, object> Dictionary { get; set; }
public DynamicJsonObject(IDictionary<string, object> dictionary)
{
this.Dictionary = dictionary;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this.Dictionary[binder.Name];
if (result is IDictionary<string, object>)
{
result = new DynamicJsonObject(result as IDictionary<string, object>);
}
else if (result is ArrayList && (result as ArrayList) is IDictionary<string, object>)
{
result = new List<DynamicJsonObject>((result as ArrayList).ToArray().Select(x => new DynamicJsonObject(x as IDictionary<string, object>)));
}
else if (result is ArrayList)
{
result = new List<object>((result as ArrayList).ToArray());
}
return this.Dictionary.ContainsKey(binder.Name);
}
}
Converter
public class DynamicJsonConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
if (type == typeof(object))
{
return new DynamicJsonObject(dictionary);
}
return null;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IEnumerable<Type> SupportedTypes
{
get { return new ReadOnlyCollection<Type>(new List<Type>(new Type[] { typeof(object) })); }
}
}
Usage (sample json):
JavaScriptSerializer jss = new JavaScriptSerializer();
jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() });
dynamic glossaryEntry = jss.Deserialize(json, typeof(object)) as dynamic;
Console.WriteLine("glossaryEntry.glossary.title: " + glossaryEntry.glossary.title);
Console.WriteLine("glossaryEntry.glossary.GlossDiv.title: " + glossaryEntry.glossary.GlossDiv.title);
Console.WriteLine("glossaryEntry.glossary.GlossDiv.GlossList.GlossEntry.ID: " + glossaryEntry.glossary.GlossDiv.GlossList.GlossEntry.ID);
Console.WriteLine("glossaryEntry.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.para: " + glossaryEntry.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.para);
foreach (var also in glossaryEntry.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso)
{
Console.WriteLine("glossaryEntry.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso: " + also);
}
This method has to return true, otherwise it will throw an error. E.g. you can throw an error if a key does not exist.
Returning true and emptying result will return an empty value rather than throwing an error.
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (!this.Dictionary.ContainsKey(binder.Name))
{
result = "";
}
else
{
result = this.Dictionary[binder.Name];
}
if (result is IDictionary<string, object>)
{
result = new DynamicJsonObject(result as IDictionary<string, object>);
}
else if (result is ArrayList && (result as ArrayList) is IDictionary<string, object>)
{
result = new List<DynamicJsonObject>((result as ArrayList).ToArray().Select(x => new DynamicJsonObject(x as IDictionary<string, object>)));
}
else if (result is ArrayList)
{
result = new List<object>((result as ArrayList).ToArray());
}
return true; // this.Dictionary.ContainsKey(binder.Name);
}
Your data class doesn't match the JSON object. Use this instead:
[DataContract]
public class GoogleSearchResults
{
[DataMember]
public ResponseData responseData { get; set; }
}
[DataContract]
public class ResponseData
{
[DataMember]
public IEnumerable<Results> results { get; set; }
}
[DataContract]
public class Results
{
[DataMember]
public string unescapedUrl { get; set; }
[DataMember]
public string url { get; set; }
[DataMember]
public string visibleUrl { get; set; }
[DataMember]
public string cacheUrl { get; set; }
[DataMember]
public string title { get; set; }
[DataMember]
public string titleNoFormatting { get; set; }
[DataMember]
public string content { get; set; }
}
Also, you don't have to instantiate the class to get its type for deserialization:
public static T Deserialise<T>(string json)
{
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
var serialiser = new DataContractJsonSerializer(typeof(T));
return (T)serialiser.ReadObject(ms);
}
}
I just think the whole example would be useful. This is the example for this problem.
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.ServiceModel.Web;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Text;
using System.Collections.Generic;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
GoogleSearchResults g1 = new GoogleSearchResults();
const string json = #"{""responseData"": {""results"":[{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://www.cheese.com/"",""url"":""http://www.cheese.com/"",""visibleUrl"":""www.cheese.com"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:bkg1gwNt8u4J:www.cheese.com"",""title"":""\u003cb\u003eCHEESE\u003c/b\u003e.COM - All about \u003cb\u003echeese\u003c/b\u003e!."",""titleNoFormatting"":""CHEESE.COM - All about cheese!."",""content"":""\u003cb\u003eCheese\u003c/b\u003e - everything you want to know about it. Search \u003cb\u003echeese\u003c/b\u003e by name, by types of milk, by textures and by countries.""},{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://en.wikipedia.org/wiki/Cheese"",""url"":""http://en.wikipedia.org/wiki/Cheese"",""visibleUrl"":""en.wikipedia.org"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:n9icdgMlCXIJ:en.wikipedia.org"",""title"":""\u003cb\u003eCheese\u003c/b\u003e - Wikipedia, the free encyclopedia"",""titleNoFormatting"":""Cheese - Wikipedia, the free encyclopedia"",""content"":""\u003cb\u003eCheese\u003c/b\u003e is a food consisting of proteins and fat from milk, usually the milk of cows, buffalo, goats, or sheep. It is produced by coagulation of the milk \u003cb\u003e...\u003c/b\u003e""},{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://www.ilovecheese.com/"",""url"":""http://www.ilovecheese.com/"",""visibleUrl"":""www.ilovecheese.com"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:GBhRR8ytMhQJ:www.ilovecheese.com"",""title"":""I Love \u003cb\u003eCheese\u003c/b\u003e!, Homepage"",""titleNoFormatting"":""I Love Cheese!, Homepage"",""content"":""The American Dairy Association\u0026#39;s official site includes recipes and information on nutrition and storage of \u003cb\u003echeese\u003c/b\u003e.""},{""GsearchResultClass"":""GwebSearch"",""unescapedUrl"":""http://www.gnome.org/projects/cheese/"",""url"":""http://www.gnome.org/projects/cheese/"",""visibleUrl"":""www.gnome.org"",""cacheUrl"":""http://www.google.com/search?q\u003dcache:jvfWnVcSFeQJ:www.gnome.org"",""title"":""\u003cb\u003eCheese\u003c/b\u003e"",""titleNoFormatting"":""Cheese"",""content"":""\u003cb\u003eCheese\u003c/b\u003e uses your webcam to take photos and videos, applies fancy special effects and lets you share the fun with others. It was written as part of Google\u0026#39;s \u003cb\u003e...\u003c/b\u003e""}],""cursor"":{""pages"":[{""start"":""0"",""label"":1},{""start"":""4"",""label"":2},{""start"":""8"",""label"":3},{""start"":""12"",""label"":4},{""start"":""16"",""label"":5},{""start"":""20"",""label"":6},{""start"":""24"",""label"":7},{""start"":""28"",""label"":8}],""estimatedResultCount"":""14400000"",""currentPageIndex"":0,""moreResultsUrl"":""http://www.google.com/search?oe\u003dutf8\u0026ie\u003dutf8\u0026source\u003duds\u0026start\u003d0\u0026hl\u003den-GB\u0026q\u003dcheese""}}, ""responseDetails"": null, ""responseStatus"": 200}";
g1 = JSONHelper.Deserialise<GoogleSearchResults>(json);
foreach (Pages x in g1.responseData.cursor.pages)
{
// Anything you want to get
Response.Write(x.label);
}
}
}
public class JSONHelper
{
public static T Deserialise<T>(string json)
{
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
var serialiser = new DataContractJsonSerializer(typeof(T));
return (T)serialiser.ReadObject(ms);
}
}
public static string Serialize<T>(T obj)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
return Encoding.Default.GetString(ms.ToArray());
}
}
}
[DataContract]
public class GoogleSearchResults
{
[DataMember]
public ResponseData responseData { get; set; }
[DataMember]
public string responseStatus { get; set; }
}
public class ResponseData
{
[DataMember]
public Cursor cursor { get; set; }
[DataMember]
public IEnumerable<Results> results { get; set; }
}
[DataContract]
public class Cursor
{
[DataMember]
public IEnumerable<Pages> pages { get; set; }
}
[DataContract]
public class Pages
{
[DataMember]
public string start { get; set; }
[DataMember]
public string label { get; set; }
}
[DataContract]
public class Results
{
[DataMember]
public string unescapedUrl { get; set; }
[DataMember]
public string url { get; set; }
[DataMember]
public string visibleUrl { get; set; }
[DataMember]
public string cacheUrl { get; set; }
[DataMember]
public string title { get; set; }
[DataMember]
public string titleNoFormatting { get; set; }
[DataMember]
public string content { get; set; }
}
I tried to use the code above but didn't work. The JSON structure returned by Google is so different and there is a very important miss in the helper function: a call to DataContractJsonSerializer.ReadObject() that actually deserializes the JSON data into the object.
Here is the code that WORKS in 2011:
using System;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Text;
using System.Collections.Generic;
namespace <YOUR_NAMESPACE>
{
public class JSONHelper
{
public static T Deserialise<T>(string json)
{
T obj = Activator.CreateInstance<T>();
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
DataContractJsonSerializer serialiser = new DataContractJsonSerializer(obj.GetType());
obj = (T)serialiser.ReadObject(ms);
ms.Close();
return obj;
}
}
public class Result
{
public string GsearchResultClass { get; set; }
public string unescapedUrl { get; set; }
public string url { get; set; }
public string visibleUrl { get; set; }
public string cacheUrl { get; set; }
public string title { get; set; }
public string titleNoFormatting { get; set; }
public string content { get; set; }
}
public class Page
{
public string start { get; set; }
public int label { get; set; }
}
public class Cursor
{
public string resultCount { get; set; }
public Page[] pages { get; set; }
public string estimatedResultCount { get; set; }
public int currentPageIndex { get; set; }
public string moreResultsUrl { get; set; }
public string searchResultTime { get; set; }
}
public class ResponseData
{
public Result[] results { get; set; }
public Cursor cursor { get; set; }
}
public class GoogleSearchResults
{
public ResponseData responseData { get; set; }
public object responseDetails { get; set; }
public int responseStatus { get; set; }
}
}
To get the content of the first result, do:
GoogleSearchResults googleResults = new GoogleSearchResults();
googleResults = JSONHelper.Deserialise<GoogleSearchResults>(jsonData);
string contentOfFirstResult = googleResults.responseData.results[0].content;
Thank you all for your help.
This is my final version, and it works thanks to your combined help !
I am only showing the changes i made, all the rest is taken from Joe Chung's work
public class GoogleSearchResults
{
[DataMember]
public ResponseData responseData { get; set; }
[DataMember]
public string responseDetails { get; set; }
[DataMember]
public int responseStatus { get; set; }
}
and
[DataContract]
public class ResponseData
{
[DataMember]
public List<Results> results { get; set; }
}
Google Map API request and parse DirectionsResponse with C#, change the json in your url to xml
and use the following code to turn the result into a usable C# Generic List Object.
Took me a while to make. But here it is
var url = String.Format("http://maps.googleapis.com/maps/api/directions/xml?...");
var result = new System.Net.WebClient().DownloadString(url);
var doc = XDocument.Load(new StringReader(result));
var DirectionsResponse = doc.Elements("DirectionsResponse").Select(l => new
{
Status = l.Elements("status").Select(q => q.Value).FirstOrDefault(),
Route = l.Descendants("route").Select(n => new
{
Summary = n.Elements("summary").Select(q => q.Value).FirstOrDefault(),
Leg = n.Elements("leg").ToList().Select(o => new
{
Step = o.Elements("step").Select(p => new
{
Travel_Mode = p.Elements("travel_mode").Select(q => q.Value).FirstOrDefault(),
Start_Location = p.Elements("start_location").Select(q => new
{
Lat = q.Elements("lat").Select(r => r.Value).FirstOrDefault(),
Lng = q.Elements("lng").Select(r => r.Value).FirstOrDefault()
}).FirstOrDefault(),
End_Location = p.Elements("end_location").Select(q => new
{
Lat = q.Elements("lat").Select(r => r.Value).FirstOrDefault(),
Lng = q.Elements("lng").Select(r => r.Value).FirstOrDefault()
}).FirstOrDefault(),
Polyline = p.Elements("polyline").Select(q => new
{
Points = q.Elements("points").Select(r => r.Value).FirstOrDefault()
}).FirstOrDefault(),
Duration = p.Elements("duration").Select(q => new
{
Value = q.Elements("value").Select(r => r.Value).FirstOrDefault(),
Text = q.Elements("text").Select(r => r.Value).FirstOrDefault(),
}).FirstOrDefault(),
Html_Instructions = p.Elements("html_instructions").Select(q => q.Value).FirstOrDefault(),
Distance = p.Elements("distance").Select(q => new
{
Value = q.Elements("value").Select(r => r.Value).FirstOrDefault(),
Text = q.Elements("text").Select(r => r.Value).FirstOrDefault(),
}).FirstOrDefault()
}).ToList(),
Duration = o.Elements("duration").Select(p => new
{
Value = p.Elements("value").Select(q => q.Value).FirstOrDefault(),
Text = p.Elements("text").Select(q => q.Value).FirstOrDefault()
}).FirstOrDefault(),
Distance = o.Elements("distance").Select(p => new
{
Value = p.Elements("value").Select(q => q.Value).FirstOrDefault(),
Text = p.Elements("text").Select(q => q.Value).FirstOrDefault()
}).FirstOrDefault(),
Start_Location = o.Elements("start_location").Select(p => new
{
Lat = p.Elements("lat").Select(q => q.Value).FirstOrDefault(),
Lng = p.Elements("lng").Select(q => q.Value).FirstOrDefault()
}).FirstOrDefault(),
End_Location = o.Elements("end_location").Select(p => new
{
Lat = p.Elements("lat").Select(q => q.Value).FirstOrDefault(),
Lng = p.Elements("lng").Select(q => q.Value).FirstOrDefault()
}).FirstOrDefault(),
Start_Address = o.Elements("start_address").Select(q => q.Value).FirstOrDefault(),
End_Address = o.Elements("end_address").Select(q => q.Value).FirstOrDefault()
}).ToList(),
Copyrights = n.Elements("copyrights").Select(q => q.Value).FirstOrDefault(),
Overview_polyline = n.Elements("overview_polyline").Select(q => new
{
Points = q.Elements("points").Select(r => r.Value).FirstOrDefault()
}).FirstOrDefault(),
Waypoint_Index = n.Elements("waypoint_index").Select(o => o.Value).ToList(),
Bounds = n.Elements("bounds").Select(q => new
{
SouthWest = q.Elements("southwest").Select(r => new
{
Lat = r.Elements("lat").Select(s => s.Value).FirstOrDefault(),
Lng = r.Elements("lng").Select(s => s.Value).FirstOrDefault()
}).FirstOrDefault(),
NorthEast = q.Elements("northeast").Select(r => new
{
Lat = r.Elements("lat").Select(s => s.Value).FirstOrDefault(),
Lng = r.Elements("lng").Select(s => s.Value).FirstOrDefault()
}).FirstOrDefault(),
}).FirstOrDefault()
}).FirstOrDefault()
}).FirstOrDefault();
I hope this will help someone.

Categories