我正在寻找一种方法,最好使用 JSON.NET(使用最新版本),将多个外部 JSON 格式/结构反序列化为单个类。
简化示例(差异大于此,但不同的 JSON 包含类似的信息):
外部 1
{
"id": 1234,
"person": {
"name": "john",
"surname": "doe"
}
}
外部 2
{
"ref": "1234",
"firstName": "JOHN",
"lastName": "DOE"
}
内部(这不是真的,只是为了展示)
{
"tag": "1234",
"name1": "John",
"name2": "Doe"
}
是否有某种方法/库可能允许您使用 mapping.json 文件配置映射。最好是还允许格式化值等的。这些只是 2 个例子,但我们还有更多。
编辑:我们可以告诉/提示 JSON.NET 给定的 JSON 来自哪个来源。因此,我们不必有一个可以处理所有不同场景的模式/合约/解决方案。我们实际上更愿意为每个不同的外部 json 结构提供一个 .json 映射/转换配置文件(以使其面向未来,而无需重建所有内容)。
编辑 2:我现在所做的是基于Pavel Baravik的答案是遍历"模式/转换"JSON的所有属性。此 JSON 与我们要将原始外部 JSON 转换为的对象的最终 JSON 具有相同的结构。如果令牌的类型为"字符串",我们将解析该字符串(支持 {{ }} 和纯 =),并将其用作从原始外部 JSON 中提取值的路径。与此同时,正在构建最终的 JSON,之后将反序列化为我们的内部对象。
我认为我们可以通过使用表达式树"排序"编译来提高此代码的性能。
static void Main(string[] args)
{
var schema = @"
{
""person"": {
""name"": ""=test.firstName"",
""fullName"": ""{{test.firstName}} {{lastName}}"",
""surName"": ""=lastName""
}
}";
var json1 = @"
{
""test"": {
""firstName"": ""John""
},
""lastName"": ""Doe"",
}";
Console.WriteLine(Transform(json1, schema).ToString());
Console.ReadLine();
}
public static JObject Transform(string json, string schema)
{
var j = JObject.Parse(json);
var s = JObject.Parse(schema);
var t = Transform(s, j);
return t;
}
public static JObject Transform(JObject schema, JObject source)
{
var target = new JObject();
foreach (var child in schema.Children())
{
var property = child as JProperty;
if (property != null)
{
var schemaToken = property.Value;
var allowClone = true;
JToken t = null;
if (schemaToken.Type == JTokenType.Object)
{
t = Transform((JObject) schemaToken, source);
}
else if (schemaToken.Type == JTokenType.String)
{
allowClone = false;
t = TransformProperty(source, (JValue)schemaToken);
}
if (t != null || allowClone)
{
target.Add(property.Name, (t ?? property).DeepClone());
}
}
}
return target;
}
private static readonly Regex MoustacheRegex = new Regex(@"{{[^}]+}}", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.Singleline);
private static JToken TransformProperty(JObject source, JValue jstring)
{
var str = (string)jstring.Value;
JToken t = null;
// if string starts with =
if (str.StartsWith("="))
{
t = GetTokenByPath(source, str.Substring(1));
}
else
{
var allFound = true;
str = MoustacheRegex.Replace(str, m =>
{
var mv = m.Value;
var mt = GetTokenByPath(source, mv.Substring(2, mv.Length - 4));
if (mt == null) allFound = false;
return mt?.ToString() ?? string.Empty;
});
if (allFound)
t = new JValue(str.Trim());
}
return t;
}
private static JToken GetTokenByPath(JObject source, string path)
{
JToken t = null;
var pathItems = path.Split('.');
var s = source;
for (var i = 0; i < pathItems.Length && s != null; ++i, s = t as JObject)
{
t = s[pathItems[i]];
}
return t;
}
编辑:(不错的JTransform类)
public class JTransform
{
private InternalJTransform _internal;
public void Load(string filePath)
{
using (var stream = File.OpenRead(filePath))
using (var reader = new StreamReader(stream))
{
Load(new JsonTextReader(reader));
}
}
public void Load(string filePath, Encoding encoding)
{
using (var stream = File.OpenRead(filePath))
using (var reader = new StreamReader(stream, encoding))
{
Load(new JsonTextReader(reader));
}
}
public void Load(JsonReader reader)
{
_internal = new InternalJTransform(reader);
}
public JObject Transform(JsonReader sourceReader)
{
return _internal.Transform(sourceReader);
}
public JObject Transform(JObject source)
{
return _internal.Transform(source);
}
public T TransformObject<T>(object obj)
{
return _internal.TransformObject<T>(obj);
}
public T TransformObject<T>(JObject source, JsonSerializer serializer = null)
{
return _internal.TransformObject<T>(source, serializer);
}
#region InternalJTransform
private sealed class InternalJTransform
{
private static readonly Regex MoustacheRegex = new Regex(@"{{[^}]+}}", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.Singleline);
private JsonSerializer _serializer;
private JObject _template;
private bool _ignoreUndefined;
public InternalJTransform(JsonReader reader)
{
var json = JObject.Load(reader);
_template = json["template"] as JObject;
_serializer = new JsonSerializer();
var settings = json["settings"];
if (settings["camelCase"]?.Value<bool>() ?? false)
_serializer.ContractResolver = new CamelCasePropertyNamesContractResolver();
if (settings["ignoreNull"]?.Value<bool>() ?? false)
_serializer.NullValueHandling = NullValueHandling.Ignore;
_ignoreUndefined = (settings["ignoreUndefined"]?.Value<bool>() ?? settings["ignoreNull"]?.Value<bool>() ?? false);
}
private void Load(JsonReader reader)
{
var json = JObject.Load(reader);
var template = json["template"] as JObject;
var serializer = new JsonSerializer();
var settings = json["settings"];
if (settings["camelCase"]?.Value<bool>() ?? false)
serializer.ContractResolver = new CamelCasePropertyNamesContractResolver();
if (settings["ignoreNull"]?.Value<bool>() ?? false)
serializer.NullValueHandling = NullValueHandling.Ignore;
_ignoreUndefined = (settings["ignoreNull"]?.Value<bool>() ?? false);
_serializer = serializer;
_template = template;
}
public JObject Transform(JsonReader sourceReader)
{
var obj = JObject.Load(sourceReader);
return TransformInternal(_template, obj, _serializer);
}
public JObject Transform(JObject source)
{
return TransformInternal(_template, source, _serializer);
}
public T TransformObject<T>(object obj)
{
var source = JObject.FromObject(obj);
var im = TransformInternal(_template, source, _serializer);
return im.ToObject<T>(_serializer);
}
public T TransformObject<T>(JObject source, JsonSerializer serializer = null)
{
var obj = TransformInternal(_template, source, _serializer);
return obj.ToObject<T>(serializer ?? _serializer);
}
private JObject TransformInternal(JObject template, JObject source, JsonSerializer serializer)
{
var ignoreNull = serializer.NullValueHandling == NullValueHandling.Ignore;
var target = new JObject();
foreach (var property in template.Properties())
{
var token = property.Value;
if (token.Type == JTokenType.Object)
{
token = TransformInternal((JObject)token, source, serializer);
}
else if (token.Type == JTokenType.String)
{
token = TransformStringToken(source, (JValue)token);
// handle undefined, not found, values
if (token == null && _ignoreUndefined) continue;
}
// handle real null values (this does not include null values set in the template)
if (token != null && token.Type == JTokenType.Null && ignoreNull) continue;
target.Add(property.Name, token?.DeepClone());
}
return target;
}
private JToken TransformStringToken(JObject source, JValue jstring)
{
var str = (string)jstring.Value;
JToken t = null;
// if string starts with =
if (str.StartsWith("="))
{
t = GetTokenByPath(source, str.Substring(1));
}
else
{
var allFound = true;
str = MoustacheRegex.Replace(str, m =>
{
var mv = m.Value;
var mt = GetTokenByPath(source, mv.Substring(2, mv.Length - 4));
if (mt == null) allFound = false;
return mt?.ToString() ?? string.Empty;
});
if (allFound)
t = new JValue(str.Trim());
}
return t;
}
private static JToken GetTokenByPath(JObject source, string path)
{
JToken t = null;
var pathItems = path.Split('.');
var s = source;
for (var i = 0; i < pathItems.Length && s != null; ++i, s = t as JObject)
{
t = s[pathItems[i]];
}
return t;
}
}
#endregion
}
您可以首先使用 JsonReader "展平"输入结构,然后映射到单个类(从反序列化特定属性 JSON.NET 采用)。
void Main()
{
var json0 = @"{
""id"": 1234,
""person"": {
""name"": ""john"",
""surname"": ""doe""
}";
var json1 = @" {
""ref"": ""1234"",
""firstName"": ""JOHN"",
""lastName"": ""DOE""
}";
foreach (var j in new []{json0, json1})
{
var name = GetFirstInstance<string>(new [] {"person.name", "firstName", "name1"}, j);
var surname = GetFirstInstance<string> (new [] {"person.surname", "lastName", "name2"}, j);
new {name, surname}.Dump();
}
}
public T GetFirstInstance<T>(string[] path, string json)
{
using (var stringReader = new StringReader(json))
using (var jsonReader = new JsonTextReader(stringReader))
{
while (jsonReader.Read())
{
if (jsonReader.TokenType == JsonToken.PropertyName && path.Contains((string)jsonReader.Path))
{
jsonReader.Read();
var serializer = new JsonSerializer();
return serializer.Deserialize<T>(jsonReader);
}
}
return default(T);
}
}
看看 CustomCreationConverter 在 JSON.NET http://www.newtonsoft.com/json/help/html/CustomCreationConverter.htm 您可以创建不同的转换器,并根据您拥有的 JSON 决定使用哪一个。 他们都可以输出相同的类