问题
I have the following JSON structure :
{
"Name":"",
"Children":[
{
"ID":"1",
"MetaData":[
{
"Info":{
"GUID":"cdee360d-7ea9-477d-994f-12f492b9e1ed"
},
"Data":{
"Text":"8"
},
"Name":"DataId"
}
]
}
]
}
and I want to flatten the MetaData and nested Info and Data objects in the array. I also want to use the Name field as a field name for Text value so it becomes "DataId" : "8".
{
"Name":"",
"Children":[
{
"ID":"1",
"GUID":"cdee360d-7ea9-477d-994f-12f492b9e1ed",
"DataId":"8"
}
]
}
So far I've used a Contract Resolver to get me so far:
private class DynamicContractResolver : DefaultContractResolver
{
private readonly List<string> _propertiesToSerialize;
private readonly List<string> _itemTypeNames;
public DynamicContractResolver(List<string> propertiesToSerialize, List<string> itemTypeNames)
{
_propertiesToSerialize = propertiesToSerialize;
_itemTypeNames = itemTypeNames;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
properties = properties.Where(p => _propertiesToSerialize.Contains(p.PropertyName)).ToList();
}
return properties;
}
}
How do I go about getting my desired serialisation?
回答1:
If you don't want to modify your types at all, you can use LINQ to JSON to load and preprocess your JSON, like so:
// Load the JSON into an intermediate JObject
var rootObj = JObject.Parse(json);
// Restructure the JObject hierarchy
foreach (var obj in rootObj.SelectTokens("Children[*]").OfType<JObject>())
{
var metadata = obj.SelectToken("MetaData[0]"); // Get the first entry in the "MetaData" array.
if (metadata != null)
{
// Remove the entire "Metadata" property.
metadata.Parent.RemoveFromLowestPossibleParent();
// Set the name and value
var name = metadata.SelectToken("Name");
var id = metadata.SelectToken("Data.Text");
if (name != null && id != null)
obj[(string)name] = (string)id;
// Move all other atomic values.
foreach (var value in metadata.SelectTokens("..*").OfType<JValue>().Where(v => v != id && v != name).ToList())
value.MoveTo(obj);
}
}
Debug.WriteLine(rootObj);
// Now deserialize the preprocessed JObject to the final class
var root = rootObj.ToObject<RootObject>();
Using a couple of simple extension methods for convenience:
public static class JsonExtensions
{
public static void RemoveFromLowestPossibleParent(this JToken node)
{
if (node == null)
throw new ArgumentNullException();
var contained = node.AncestorsAndSelf().Where(t => t.Parent is JArray || t.Parent is JObject).FirstOrDefault();
if (contained != null)
contained.Remove();
}
public static void MoveTo(this JToken token, JObject newParent)
{
if (newParent == null)
throw new ArgumentNullException();
var toMove = token.AncestorsAndSelf().OfType<JProperty>().First(); // Throws an exception if no parent property found.
toMove.Remove();
newParent.Add(toMove);
}
}
来源:https://stackoverflow.com/questions/31046448/json-serialisation-how-to-flatten-nested-object-structures-using-json-net-newt