Reputation: 3
I am currently consuming JSON output from one source that contains an array and one that does not.
The one with an array is simple, as I can create a class that represents the object and the list of objects, then iterate through the list and get the properties for each object. In the source that does not have an array, however, it is throwing me for a loop.
I do not know how to iterate through this. It seems as if I would need to create separate classes for "abc" and "def" even though the properties of each class are the same. Is there a simple way to do this?
Example that does not contain an array:
{
"objectContainer": {
"count": 25,
"objects": {
"abc": {
"name": "object1",
"parent": "0",
"status": "0",
},
"def": {
"name": "object2",
"parent": "0",
"status": "0",
}
etc....
Thanks in advance for any assistance.
Upvotes: 0
Views: 167
Reputation: 7830
You could use the excellent (and dynamic) JObject class from the JSON.NET library like this:
// example input
var json = @"{""objectContainer"": {
""count"": 25,
""objects"": {
""abc"": {
""name"": ""object1"",
""parent"": ""0"",
""status"": ""0"",
},
""def"": {
""name"": ""object2"",
""parent"": ""0"",
""status"": ""0"",
}
}}";
var obj = JsonConvert.DeserializeObject(json);
var objectContainer = ((JObject)obj)["objectContainer"];
var abc = objectContainer["objects"]["abc"];
Console.WriteLine(abc["name"]);
The output is:
output1
You could even use directly the JObject.Parse() method to load and parse just a JSON code portion (for example if you can extract only the abc
part from the complete JSON string):
var abc = JObject.Parse(@"{""abc"": {
""name"": ""object1"",
""parent"": ""0"",
""status"": ""0"",
}}")["abc"];
Console.WriteLine(abc["name"]);
var abcd = JObject.Parse(@"{
""name"": ""object1"",
""parent"": ""0"",
""status"": ""0"",
}");
Console.WriteLine(abcd["name"]);
You could then assign the extracted values to your custom class.
Using the library and the JObject class you don't need to represent the JSON with a class. The downside is, that you don't have the type safety of the class and it's properties.
Update
You could iterate over the properties / objects without knowing their names:
var obj = JsonConvert.DeserializeObject(json);
var objectContainer = ((JObject)obj)["objectContainer"];
foreach (var o in objectContainer["objects"])
{
if (o is JProperty)
{
var op = ((JProperty)o);
Console.WriteLine("{0} - {1}", op.Name, op.Value);
}
}
The output is:
abc - {
"name": "object1",
"parent": "0",
"status": "0"
}
def - {
"name": "object2",
"parent": "0",
"status": "0"
}
Upvotes: 0
Reputation: 18155
You could use inheritance to prevent repeating the properties for "abc" and "def" over and over again.
public class Base
{
public string name { get; set; }
public string parent { get; set; }
public string status { get; set; }
}
public class Abc : Base { }
public class Def : Base { }
public class Objects
{
public Abc abc { get; set; }
public Def def { get; set; }
}
public class ObjectContainer
{
public int count { get; set; }
public Objects objects { get; set; }
}
public class RootObject
{
public ObjectContainer objectContainer { get; set; }
}
Then using JSON.NET you can deserialize the string.
var root = JsonConvert.DeserializeObject<RootObject>( json );
The problem is you're going to have to change the code every time you get a new object in there (e.g. ghi).
Another option, particularly if you're going to have different object names showing up, would be to just parse the JSON serially yourself.
JsonTextReader reader = new JsonTextReader( new StringReader( json ) );
while( reader.Read() )
{
if( reader.Value != null )
{
Console.WriteLine( "Field: {0}, Value: {1}", reader.TokenType, reader.Value );
}
}
Obviously where it's writing output to the Console you'd have to examine the TokenType and Value and stuff those into an object.
Update
This is pretty ugly, but I was curious how I might parse this into the object structure. You'd need to change the receiving object definitions a bit.
public class Base
{
public string name { get; set; }
public string parent { get; set; }
public string status { get; set; }
}
public class Objects
{
public List<Base> bases { get; set; }
public Objects()
{
bases = new List<Base>();
}
}
public class ObjectContainer
{
public int count { get; set; }
public Objects objects { get; set; }
public ObjectContainer()
{
objects = new Objects();
}
}
public class RootObject
{
public ObjectContainer objectContainer { get; set; }
public RootObject()
{
objectContainer = new ObjectContainer();
}
}
Then you can parse into it using:
while( reader.Read() )
{
if( reader.Value != null )
{
switch( reader.Depth )
{
case 2:
if( reader.TokenType == JsonToken.PropertyName && reader.Value.ToString() == "count" )
{
reader.Read();
root.objectContainer.count = Convert.ToInt32( reader.Value );
}
break;
case 3:
newBase = new Base();
root.objectContainer.objects.bases.Add( newBase );
break;
case 4:
if( reader.TokenType == JsonToken.PropertyName && reader.Value.ToString() == "name" )
{
reader.Read();
newBase.name = reader.Value.ToString();
}
if( reader.TokenType == JsonToken.PropertyName && reader.Value.ToString() == "parent" )
{
reader.Read();
newBase.parent = reader.Value.ToString();
}
if( reader.TokenType == JsonToken.PropertyName && reader.Value.ToString() == "status" )
{
reader.Read();
newBase.status = reader.Value.ToString();
}
break;
}
}
}
Not the prettiest code in the world but as long as the structure of the JSON doesn't change you'll end up with a nice object model no matter how many child objects or what their names are.
Upvotes: 1
Reputation: 1627
Based on your JSON above, you would probably need to create classes for those objects. You can abstract some of it away with inheritance as well. If possible, it would make more sense for "objects" to be an array that way you don't need to create separate objects. The name, and implementation both suggest an array.
If you cannot change the structure of the JSON, have a look at the bottom of the page at http://json.org/ for different libraries. Some may be more helpful than others. Json.NET is the one I usually use and you may have better results using something like their JSonReader so you don't have to create an overly complex object structure.
Upvotes: 0