public class Rootobject
{
public EnPickthall enpickthall { get; set; }
}
public class EnPickthall
{
public _1 _1 { get; set; }
public _2 _2 { get; set; }
public _3 _3 { get; set; }
public _4 _4 { get; set; }
/* This goes on*/
public _6236 _6236 { get; set;}
}
//For Each of the above properties a separate class has been defined:
public class _1
{
public int id { get; set; }
public int surah { get; set; }
public int ayah { get; set; }
public string verse { get; set; }
}
public class _2
{
public int id { get; set; }
public int surah { get; set; }
public int ayah { get; set; }
public string verse { get; set; }
}
/* So On for all the properties */
I got this via JSON2CSHARP!
My problem is if I employ so many properties retrieving all Verses based upon their "Surah" would be very difficult & Impractical
Here I have a book in EnPickthall class which has a separate Class for every verse. Every Verse here has it's own class.
I have been scavenging Stack Overflow for hours.Is there any way I could simplify this JSON Classes.
My Code to Creating the object model :
var serializer = new DataContractJsonSerializer(typeof(RootObject_Quran));
var result= App_Code.FileIOHelper.ReadFromDefaultFile("ms-appx:///Assets/en.pickthall.json");
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject_Quran)serializer.ReadObject(ms);
My JSON File Link : http://globalquran.com/download/data/download.php?data_by=json&quran_by_id[]=en.pickthall
Just have a single class called Verse.
public class Verse {
public int SurahId { get; set; }
public int AyaId { get; set; }
public String Text { get; set; }
}
You don't really need a key for each verse, as the surah/aya combination is sufficient to uniquely identify a verse.
This allows for easy serialization/deserialization and also allows for easy gathering into the entire Quran again, by ordering on Surah and Aya. You could then simply use LINQ to reassemble the entire book, ordered as state above. Or it would be incredibly simple to gather passages from it also, based on a search criteria e.g. 27:18-20
Json is nested with property en.pickthall than all data wrapper again into property like id numbers so i made class and that class has Dictionary to handle data and numbers
[JsonProperty(PropertyName = "en.pickthall")]
public Dictionary picthall {get;set;}
public class VerseObject
{
[JsonProperty(PropertyName = "en.pickthall")]
public Dictionary<int, Data> picthall {get;set;}
}
public class Data
{
[JsonProperty(PropertyName = "id")]
public int id;
[JsonProperty(PropertyName = "surah")]
public int surah;
[JsonProperty(PropertyName = "ayah")]
public int ayah;
[JsonProperty(PropertyName = "verse")]
public string verse;
}
class Program
{
static void Main(string[] args)
{
List<Data> v = new List<Data>();
using (StreamReader rdr = new StreamReader(#"C:\Temp\en.pickthall.json"))
{
var str = rdr.ReadToEnd();
var jsn = JsonConvert.DeserializeObject<VerseObject>(str);
foreach(var item in jsn.picthall.Select(x=>x.Value))
{
v.Add(item);
}
Console.ReadLine();
}
}
}
Related
I am working on a Xamarin.Forms Project and I am at a dead-end of sorts. My issue is that I want to display user transactions which I pull from a server, in a listview, however I need four different pull requests to get all the data which means I have four different objects lists which I grouped by the transaction number as you can see in this screenshot:
The key transaction number can be seen and if you expand you'll see the other data within each transaction
Here is the code where I group the deserialised json lists with the common key:
var t = JsonConvert.DeserializeObject<List<trans_mod>>(transactions);
var l = JsonConvert.DeserializeObject<List<loc_mod>>(loc);
var d = JsonConvert.DeserializeObject<List<disc_mod>>(disc);
var it = JsonConvert.DeserializeObject<List<item_mod>>(itm);
var q = it.AsQueryable().GroupBy(g => g.trans).ToList();
var q2= d.AsQueryable().GroupBy(g => g.trans).ToList();
var q3 = l.AsQueryable().GroupBy(g => g.trans).ToList();
var q4 = t.AsQueryable().GroupBy(g => g.position).ToList();
Object Models for each list
public class loc_mod
{
[DataMember]
public string location { get; set; }
[JsonProperty(PropertyName = "#modify_stamp")]
public string stamp { get; set; }
[JsonProperty(PropertyName = "$trans")]
public string trans { get; set; }
}
public class disc_mod
{
[DataMember]
public string discount { get; set; }
[JsonProperty(PropertyName = "#modify_stamp")]
public string stamp { get; set; }
[JsonProperty(PropertyName = "$trans")]
public string trans { get; set; }
}
public class item_mod
{
[JsonProperty(PropertyName = "item.price")]
public string price { get; set; }
[JsonProperty(PropertyName = "item.name")]
public string name { get; set; }
[JsonProperty(PropertyName = "#modify_stamp")]
public string stamp { get; set; }
[JsonProperty(PropertyName = "$trans")]
public string trans { get; set; }
}
public class trans_mod
{
[DataMember]
public string refer { get; set; }
[DataMember]
public string date { get; set; }
[DataMember]
public string time { get; set; }
[DataMember]
public int points { get; set; }
[DataMember]
public string _total { get; set; }
[JsonProperty(PropertyName = "$$position")]
public string position { get; set; }
[JsonProperty(PropertyName = "#modify_stamp")]
public string stamp { get; set; }
[JsonProperty(PropertyName = "$trans")]
public string trans { get; set; }
}
public class itms
{
public string price { get; set; }
public string name { get; set; }
public DateTime stamp { get; set; }
[JsonProperty(PropertyName = "$trans")]
public string trans { get; set; }
}
What I want to do is to loop through all four lists and add the data from each list in the listview but I can't think of a way I can do that.
Listview Add() code Example:
Transactions.Add(new Transaction
{
Details = "Date: " + ti[i].date + " | Time: " + ti[i].time + " |
Reference: " + ti[i].refer,
Isvisible = false, Items= ti[i].item, Total = ti[i].total, Discount
= ti[i].discount
});
Sorry if this is a bit confusing, it's confusing for me as well as I am a relative beginner. Any help is welcome!
Define an Interface that your item classes all implement.
That interface has a method that returns whatever you need for listview.
public Interface IHasTransaction
{
Transaction GetTransaction();
}
public class loc_mod : IHasTransaction
{
...
public Transaction GetTransaction()
{
// Use fields of this class to create a Transaction.
return new Transaction(...);
}
}
public class disc_mod : IHasTransaction
{
...
}
If you want, you can make a list that has a mixture of these:
public List<IHasTransaction> models = new List<IHasTransaction>();
models.Add(new loc_mod(...));
models.Add(new disc_mod(...));
Given any of these items
IHasTransaction model
You can easily get the corresponding Transaction:
model.GetTransaction()
OR
var lm = new loc_mod(...);
lm.GetTransaction()
I have the XML below:
<y:input xmlns:y='http://www.blahblah.com/engine/42'>
<y:datas>
<y:instance yclass='ReportPeriod' yid="report">
<language yid='en'/>
<threshold>0.6</threshold>
<typePeriod>predefinedPeriod</typePeriod>
<interval>month</interval>
<valuePeriod>April</valuePeriod>
<fund yclass="Fund">
<name>K</name>
<indexName>CAC40</indexName>
</fund>
</y:instance>
</y:datas>
</y:input>
That I am trying to deserialize to
[XmlRoot(ElementName="fund")]
public class Fund
{
[XmlElement(ElementName="name")]
public string Name { get; set; }
[XmlElement(ElementName="indexName")]
public string IndexName { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
}
[XmlRoot(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
public class Instance
{
[XmlElement(ElementName="language")]
public Language Language { get; set; }
[XmlElement(ElementName="threshold")]
public string Threshold { get; set; }
[XmlElement(ElementName="typePeriod")]
public string TypePeriod { get; set; }
[XmlElement(ElementName="interval")]
public string Interval { get; set; }
[XmlElement(ElementName="valuePeriod")]
public string ValuePeriod { get; set; }
[XmlElement(ElementName="fund")]
public Fund Fund { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
[XmlAttribute(AttributeName="yid")]
public string Yid { get; set; }
}
[XmlRoot(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public class Datas
{
[XmlElement(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
public Instance Instance { get; set; }
}
[XmlRoot(ElementName="input", Namespace="http://www.blahblah.com/engine/42")]
public class Input
{
[XmlElement(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public Datas Datas { get; set; }
[XmlAttribute(AttributeName="y", Namespace="http://www.blahblah.com/engine/42", Form = XmlSchemaForm.Qualified)]
public string Y { get; set; }
}
However, when deserializing the XML above:
public static class Program
{
public static void Main(params string[] args)
{
var serializer = new XmlSerializer(typeof(Input));
using (var stringReader = new StringReader(File.ReadAllText("file.xml")))
{
using(var xmlReader = XmlReader.Create(stringReader))
{
var instance = (Input)serializer.Deserialize(stringReader);
}
}
}
}
I get an error due to the y prefix...
There is an error in XML document (1, 1). ---> System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.
Reading some posts like that one: https://stackoverflow.com/a/36163079/4636721 it seems that there is maybe a bug with the XmlSerializer.
The cause of the exception is that you are passing stringReader rather than xmlReader to serializer.Deserialize(). You should be passing the XML reader instead:
Input instance = null;
var serializer = new XmlSerializer(typeof(Input));
using (var stringReader = new StreamReader("file.xml"))
{
using(var xmlReader = XmlReader.Create(stringReader))
{
instance = (Input)serializer.Deserialize(xmlReader);
}
}
(Apparently XmlReader.Create(stringReader) advances the text reader a bit, so if you later attempt to read from the stringReader directly, it has been moved past the root element.)
You also have some errors in your data model. It should look like:
[XmlRoot(ElementName="fund")]
public class Fund
{
[XmlElement(ElementName="name")]
public string Name { get; set; }
[XmlElement(ElementName="indexName")]
public string IndexName { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
}
[XmlRoot(ElementName="instance")]
[XmlType(Namespace = "")] // Add this
public class Instance
{
[XmlElement(ElementName="language")]
public Language Language { get; set; }
[XmlElement(ElementName="threshold")]
public string Threshold { get; set; }
[XmlElement(ElementName="typePeriod")]
public string TypePeriod { get; set; }
[XmlElement(ElementName="interval")]
public string Interval { get; set; }
[XmlElement(ElementName="valuePeriod")]
public string ValuePeriod { get; set; }
[XmlElement(ElementName="fund")]
public Fund Fund { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
[XmlAttribute(AttributeName="yid")]
public string Yid { get; set; }
}
[XmlRoot(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public class Datas
{
[XmlElement(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
public Instance Instance { get; set; }
}
[XmlRoot(ElementName="input", Namespace="http://www.blahblah.com/engine/42")]
public class Input
{
[XmlElement(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public Datas Datas { get; set; }
//Remove This
//[XmlAttribute(AttributeName="y", Namespace="http://www.blahblah.com/engine/42", Form = XmlSchemaForm.Qualified)]
//public string Y { get; set; }
}
// Add this
[XmlRoot(ElementName="language")]
public class Language
{
[XmlAttribute(AttributeName="yid")]
public string Yid { get; set; }
}
Notes:
xmlns:y='http://www.blahblah.com/engine/42' is an XML namespace declaration and thus should not be mapped to a member in the data model.
The child elements of <y:instance ...> are not in any namespace. Unless the namespace of the child elements is specified by attributes somehow, XmlSerializer will assume that they should be in the same namespace as the containing element, here http://www.blahblah.com/engine/42".
Thus it is necessary to add [XmlType(Namespace = "")] to Instance to indicate the correct namespace for all child elements created from Instance. (Another option would be to add [XmlElement(Form = XmlSchemaForm.Unqualified)] to each member, but I think it is easier to set a single attribute on the type.)
A definition for Language is not included in your question, so I included one.
It will be more efficient to deserialize directly from your file using a StreamReader than to read first into a string, then deserialize from the string using a StringReader.
Working sample fiddle here.
I'm at loss here. I want to refactor a part of the code that uses no abstract classes. I'm familiar with json2csharp. That converts a JSON file to the C# classes so it can be easily deserialized.
Is there a similar site/tool that accepts as input several C# classes and generates basic abstract classes based on those?
This would make the refactoring easier as I don't need to create all the different abstract classes.
Very simple example:
Input:
public class TestClass1
{
public string TestID { get; set; }
public string TestName { get; set; }
public int TestValue1 { get; set; }
public TestClass1()
{
}
}
public class TestClass2
{
public string TestID { get; set; }
public string TestName { get; set; }
public int TestValue2 { get; set; }
public TestClass2()
{
}
}
Output:
public abstract class ATestClass
{
public string TestID { get; set; }
public string TestName { get; set; }
protected ATestClass()
{
}
}
You can get something working pretty quickly if you use the Roslyn code analysis and code generation. Here’s a quick example how that could work. Note that this is somewhat fragile with detecting common properties since its based on the syntax instead of the actual semantics (making string Foo and String Foo incompatible properties). But for code that is actually generated by another code generator, this should work fine since the input should be consistent.
var input = #"
public class TestClass1
{
public string TestID { get; set; }
public string TestName { get; set; }
public string OtherTest { get; set; }
public int TestValue1 { get; set; }
public TestClass1()
{
}
}
public class TestClass2
{
public string TestID { get; set; }
public string TestName { get; set; }
public int OtherTest { get; set; }
public int TestValue2 { get; set; }
public TestClass2()
{
}
}";
// parse input
var tree = CSharpSyntaxTree.ParseText(input);
// find class declarations and look up properties
var classes = tree.GetCompilationUnitRoot().ChildNodes()
.OfType<ClassDeclarationSyntax>()
.Select(cls => (declaration: cls, properties: cls.ChildNodes().OfType<PropertyDeclarationSyntax>().ToDictionary(pd => pd.Identifier.ValueText)))
.ToList();
// find common property names
var propertySets = classes.Select(x => new HashSet<string>(x.properties.Keys));
var commonPropertyNames = propertySets.First();
foreach (var propertySet in propertySets.Skip(1))
{
commonPropertyNames.IntersectWith(propertySet);
}
// verify that the property declarations are equivalent
var commonProperties = commonPropertyNames
.Select(name => (name, prop: classes[0].properties[name]))
.Where(cp =>
{
foreach (var cls in classes)
{
// this is not really a good way since this just syntactically compares the values
if (!cls.properties[cp.name].IsEquivalentTo(cp.prop))
return false;
}
return true;
}).ToList();
// start code generation
var workspace = new AdhocWorkspace();
var syntaxGenerator = SyntaxGenerator.GetGenerator(workspace, LanguageNames.CSharp);
// create base class with common properties
var baseClassDeclaration = syntaxGenerator.ClassDeclaration("BaseClass",
accessibility: Accessibility.Public,
modifiers: DeclarationModifiers.Abstract,
members: commonProperties.Select(cp => cp.prop));
var declarations = new List<SyntaxNode> { baseClassDeclaration };
// adjust input class declarations
commonPropertyNames = new HashSet<string>(commonProperties.Select(cp => cp.name));
foreach (var cls in classes)
{
var propertiesToRemove = cls.properties.Where(prop => commonPropertyNames.Contains(prop.Key)).Select(prop => prop.Value);
var declaration = cls.declaration.RemoveNodes(propertiesToRemove, SyntaxRemoveOptions.KeepNoTrivia);
declarations.Add(syntaxGenerator.AddBaseType(declaration, syntaxGenerator.IdentifierName("BaseClass")));
}
// create output
var compilationUnit = syntaxGenerator.CompilationUnit(declarations);
using (var writer = new StringWriter())
{
compilationUnit.NormalizeWhitespace().WriteTo(writer);
Console.WriteLine(writer.ToString());
}
This would generate the following output:
public abstract class BaseClass
{
public string TestID
{
get;
set;
}
public string TestName
{
get;
set;
}
}
public class TestClass1 : BaseClass
{
public string OtherTest
{
get;
set;
}
public int TestValue1
{
get;
set;
}
public TestClass1()
{
}
}
public class TestClass2 : BaseClass
{
public int OtherTest
{
get;
set;
}
public int TestValue2
{
get;
set;
}
public TestClass2()
{
}
}
I make a call to the Riot Games API https://developer.riotgames.com/
It returns this huge output (link to pastebin) in JSON.
The JSON contains 6 "Participants" and I want to create 6 participant objects from the output. My problem is that there are other sections than the "Participants" such as "gameid", "gamestarttime" and etc. Because of this I don't know how to read out only the JSON text under the "participants:" section.
In short, how do I get single out only the data under "participants" or how do I create only objects from the "participants" section of the output?
Here is my code that would work if there wasn't anything other than participants:
// Create a string containing the output from the API call
var jsonString = GetResponse("https://euw1.api.riotgames.com/lol/spectator/v3/active-games/by-summoner/79200188?api_key=xxxxxxxxxxxxxxxxxxxxxxxxxx");
// Create a list of Participants containing the data from the JSON
var participantsList = JsonConvert.DeserializeObject<List<Participant>>(jsonString);
// Show the names of the participants
foreach (var item in participantsList)
{
MessageBox.Show(item.summonerName);
}
Here is my Participant class which from which I want to create objects from the JSON.
class Participant
{
public int profileIconId { get; set; }
public int championId { get; set; }
public string summonerName { get; set; }
public bool bot { get; set; }
public int spell2Id { get; set; }
public int teamId { get; set; }
public int spell1Id { get; set; }
public int summonerId { get; set; }
}
As per my comment, json.net only deserializes the fields that it can find in the model. So just put only the fields you want to take from the json in the model.
Example POCO's:
public class GameData {
public string gameId {get; set;}
public int mapId {get; set;} //just demonstrating that it only fills in the fields you put in the model
public List<Participant> participants = new List<Participant>();
}
...
public class Participant
{
public int profileIconId { get; set; }
public int championId { get; set; }
public string summonerName { get; set; }
public bool bot { get; set; }
public int spell2Id { get; set; }
public int teamId { get; set; }
public int spell1Id { get; set; }
public int summonerId { get; set; }
}
Deserialize like so:
var gameInfo = JsonConvert.DeserializeObject<GameData>(jsonString);
var participantsList = gameInfo.participants;
If you have no problem in creating one more model then create a Base Model
public class GameData
{
public string gameId {get; set;}
public int mapId {get; set;}
public List<Participant> participants
}
and use
var gameData =JsonConvert.DeserializeObject<GameData>(jsonString);
If you do not want to create one more model the you can convert the jsonString to Jobject then extract out sing values or deserialize from that value
For eg,
var jsonString = GetResponse("https://euw1.api.riotgames.com/lol/spectator/v3/active-games/by-summoner/79200188?api_key=RGAPI-dc7c328a-dd2b-40ca-8ccd-71d05d530a4e");
JObject json = JObject.Parse(jsonString);
var gameId = json .GetValue("filetype").ToString();
You can do this to extract other values too
I have an API I am receiving data from. That API is out of my control on how it is structured, and I need to serialize and deserialize the JSON output to map the data to my model.
Everything works well where JSON is nicely formatted with named properties.
What can you do where there is no named value and there is just an array of ints and strings? like under locations
here is a sample of the JSON:
{"id":"2160336","activation_date":"2013-08-01","expiration_date":"2013-08-29","title":"Practice Manager","locations":{"103":"Cambridge","107":"London"}}
I have models that are like:
public class ItemResults
{
public int Id { get; set; }
public DateTime Activation_Date { get; set; }
public DateTime Expiration_Date{ get; set; }
public string Title { get; set; }
public Location Locations { get; set; }
}
public class Location
{
public int Id { get; set; }
public string value { get; set; }
}
and I am mapping using the inbuilt ajax serialization:
protected T MapRawApiResponseTo<T>( string response )
{
if ( string.IsNullOrEmpty( response ) )
{
return default( T );
}
var serialize = new JavaScriptSerializer();
return serialize.Deserialize<T>( response );
}
var results = MapRawApiResponseTo<ItemResults>(rawApiResponse);
So the ID and all other properties are picked up and mapped but what every I do I can not seem to map the locations.
Many thanks
public Dictionary<int,string> Locations { get; set; }
job done; you should find that using Json.NET, at least, i.e.
var result = JsonConvert.DeserializeObject<ItemResults>(json);
you get 2 entries in result.Locations; specifically result[103] = "Cambridge"; and result[107] = "London";
If you don't mind, you can workaround with dictionary:
class Program
{
static void Main(string[] args)
{
string json =
"{'id':'2160336','activation_date':'2013-08-01','expiration_date':'2013-08-29','title':'Practice Manager','locations':{'103':'Cambridge','107':'London'}}";
var deserializeObject = JsonConvert.DeserializeObject<ItemResults>(json);
Console.WriteLine("{0}:{1}", deserializeObject.Locations.First().Key, deserializeObject.Locations.First().Value);
Console.ReadKey();
}
}
public class ItemResults
{
public int Id { get; set; }
public DateTime Activation_Date { get; set; }
public DateTime Expiration_Date { get; set; }
public string Title { get; set; }
public Dictionary<int, string> Locations { get; set; }
}
you can also use manual parsing, like here: Json.NET (Newtonsoft.Json) - Two 'properties' with same name?
This will work:
public Dictionary<string, string> Locations { get; set; }
public IEnumerable<Location> LocationObjects { get { return Locations
.Select(x => new Location { Id = int.Parse(x.Key), value = x.Value }); } }
I propose you the following solution :
public class ItemResults
{
public int Id { get; set; }
public DateTime Activation_Date { get; set; }
public DateTime Expiration_Date { get; set; }
public string Title { get; set; }
[JsonProperty("locations")]
public JObject JsonLocations { get; set; }
[JsonIgnore]
public List<Location> Locations { get; set; }
[OnDeserialized]
public void OnDeserializedMethod(StreamingContext context)
{
this.Locations = new List<Location>();
foreach (KeyValuePair<string, JToken> item in this.JsonLocations)
{
this.Locations.Add(new Location() { Id = int.Parse(item.Key), value = item.Value.ToString() });
}
}
}
public class Location
{
public int Id { get; set; }
public string value { get; set; }
}
After you just have to deserialize your JSON with : JsonConvert.DeserializeObject<ItemResults>(json);