using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PTMedicalInsurance.Common;
using PTMedicalInsurance.Variables;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace PTMedicalInsurance.Helper
{
///
/// 将json转换为实体对象
///
public class JsonMapper
{
const string ArrayPattern = "[]";
private string jsonConfig;
private string configFile;
private JsonMappingSetting setting;
public JsonMapper(string name)
{
configFile = Global.curEvt.path + "/config/" + name + ".json";
reload();
}
public void reload()
{
try
{
// 加载字段映射配置
if (File.Exists(configFile))
{
jsonConfig = File.ReadAllText(configFile);
setting = JsonHelper.toObject(JObject.Parse(jsonConfig));
}
else
{
setting = new JsonMappingSetting();
}
}
catch (Exception ex)
{
throw new Exception("配置文件异常:"+ex.Message);
}
}
///
/// 获取入参映射
///
///
public List GetInputMapping()
{
return setting.Input??new List();
}
///
/// 设置入参
///
///
public void SetInputMapping(List value)
{
setting.Input = value;
}
///
/// 获取出参映射
///
///
public List GetOutputMapping()
{
return setting.Output ?? new List();
}
///
/// 设置出参
///
///
public void SetOutputMapping(List value)
{
setting.Output = value;
}
///
/// 获取转换类
///
///
private ConvertMapping GetConverter()
{
return setting.Convert??new ConvertMapping();
}
///
/// 根据实体类获取Json
///
///
///
private string GetConvertJson(string typeName)
{
if (!string.IsNullOrEmpty(typeName))
{
if (typeName.IndexOf(".")<1)
{
typeName = "PTMedicalInsurance.Entity.Local." + typeName;
}
Type type = Type.GetType(typeName);
if (type != null)
{
Object obj = Activator.CreateInstance(type);
return JsonHelper.toJsonString(obj, false);
}
}
return string.Empty;
}
///
/// 将参数方向对调
///
public void ChangeDirection(List mappings)
{
mappings.ForEach((map) =>
{
if (!string.IsNullOrEmpty(map.Source) && !string.IsNullOrEmpty(map.Target))
{
string orgin = map.Target;
map.Target = map.Source;
map.Source = orgin;
}
});
}
///
/// 入参实例JSON
///
///
public string GetInputJson()
{
return GetConvertJson(GetConverter()?.Input);
}
///
/// 出参实例JSON
///
///
public string GetOutputJson()
{
return GetConvertJson(GetConverter()?.Output);
}
///
/// Json字段映射
///
///
///
private JObject MapJson(string key,JObject jSource)
{
JObject jObject = new JObject();
if(string.IsNullOrEmpty(jsonConfig) || string.IsNullOrEmpty(key))
{
return jSource;
}
List fieldMappings = "input".Equals(key) ? GetInputMapping() : GetOutputMapping() ;
if (fieldMappings != null)
{
// 对于每一个字段映射信息
foreach (var fieldMapping in fieldMappings)
{
if (!string.IsNullOrEmpty(fieldMapping.Target))
{
// 单一映射或一对多统一处理
string[] targets = fieldMapping.Target.Split(",".ToCharArray());
List fields = new List();
foreach (var t in targets)
{
fields.Add(new FieldMapping()
{
Source = fieldMapping.Source,
Expression = fieldMapping.Expression,
Target = t,
Value = fieldMapping.Value,
Child = fieldMapping.Child
}) ;
}
fields.ForEach((f) =>
{
MapItem(f,jSource,jObject);
});
}
else
{
MapItem(fieldMapping, jSource, jObject);
}
}
}
return jObject;
}
private void MapItem(FieldMapping fieldMapping, JObject jSource, JObject jObject)
{
// 使用JToken.SelectToken来获取源路径对应的值
dynamic value = new JValue("");
string nameKey = fieldMapping.Source;
string expression = fieldMapping.Expression;
if (!string.IsNullOrEmpty(nameKey) && string.IsNullOrEmpty(fieldMapping.Value))
{
nameKey = nameKey.Split(",".ToCharArray())[0]; //多对一忽略后面的
//TODO: 多对一时支持按指定连接符进行连接
if (fieldMapping.Child != null)
{
//数组映射
nameKey = nameKey.Replace(ArrayPattern, "");
}
else
{
if (nameKey.Contains(ArrayPattern))
{
//数组映射对象时,取第一个
nameKey = nameKey.Replace(ArrayPattern, "[0]");
}
}
value = jSource.SelectToken(nameKey);
}
else if (fieldMapping.Value != null)
{
// 支持固定值
value = new JValue(fieldMapping.Value);
}
// 表达式(全局变量)
if ((expression ?? "").Equals("GlobaVariables"))
{
value = GetExpressionValue(expression, fieldMapping.Source);
expression = null;
}
// 表达式(扩展字段)
if ((expression ?? "").Equals("SaveToExpand"))
{
SetExpression(expression, fieldMapping.Source, value);
return;
}
string converter = "ShortDate,NoSplitDate,ConvertToString";
if (expression!=null && converter.IndexOf(expression)!=-1)
{
value = GetExpressionValue(expression, value);
expression = null;
}
// 普通转换
if (value != null)
{
if (fieldMapping.Child != null)
{
Type type = value.GetType();
var items = new JArray();
//如果为JValue,则为一对多(忽略此时的name)
if (type == typeof(JValue))
{
JObject sub = new JObject();
// 此时只返回一条数据的集合
fieldMapping.Child.ForEach((c) =>
{
MapItem(c, jSource, sub);
});
items.Add(sub);
}
else if (type == typeof(JArray))
{
//数组映射,此时的value为array
foreach (var item in (JArray)value)
{
var child = MapChildItem((JObject)item, fieldMapping.Child);
items.Add(child);
}
}
CreateJObjectFromString(jObject, fieldMapping.Target.Replace(ArrayPattern, ""), items, 0);
}
else
{
ParseAndMap(value, jObject, nameKey, fieldMapping.Target, expression);
}
}
}
///
/// 映射子对象
///
///
///
///
private JObject MapChildItem(JObject itemObject, List childs)
{
JObject newItem = new JObject();
foreach (FieldMapping subMapping in childs)
{
if (subMapping.Value != null)
{
newItem[subMapping.Target] = subMapping.Value;
}
else
{
newItem[subMapping.Target] = itemObject[subMapping.Source];
}
}
return newItem;
}
///
/// 映射实体
///
/// 源对象
/// 目标对象
/// 名称
/// 源数据
///
public TTarget Map(string key, TSource sourceItem)
{
var json = JsonConvert.SerializeObject(sourceItem);
var jObject = JObject.Parse(json);
// 映射
JObject jRet = MapJson(key,jObject);
// 然后将修改后的JObject再转化到目标类型的对象
var targetItem = jRet.ToObject();
return targetItem;
}
///
/// 解析对象后转换为JObject
///
///
///
///
///
//[Obsolete("建议使用Map方法")]
private JObject MapObject(string key,TSource sourceItem)
{
TTarget target = Map(key,sourceItem);
var json = JsonConvert.SerializeObject(target);
return JObject.Parse(json);
}
///
/// 入参映射
///
///
///
///
///
public JObject MapRequest(TSource sourceItem)
{
TTarget target = Map("input",sourceItem);
var json = JsonConvert.SerializeObject(target);
return JObject.Parse(json);
}
///
/// 出参映射
///
///
///
///
///
public JObject MapResponse(TSource sourceItem)
{
TTarget target = Map("output", sourceItem);
var json = JsonConvert.SerializeObject(target);
return JObject.Parse(json);
}
///
/// 解析并映射字段
///
///
///
///
///
private void ParseAndMap(JToken sourceToken, JObject targetObject, string sourcePath, string targetPath, string expression = "")
{
// 支持映射多个字段
var targetFields = targetPath.Split(',');
foreach (var targetField in targetFields) {
//if (!sourceToken.HasValues && string.IsNullOrEmpty(sourceToken.Value())) continue;
ParseAndMapField(sourceToken, targetObject, sourcePath, targetField, expression);
}
}
///
/// 解析并映射单个字段
///
///
///
///
///
private void ParseAndMapField(JToken value, JObject targetObject, string sourcePath, string targetPath, string expression = "")
{
if (string.IsNullOrEmpty(targetPath)) return;
if (sourcePath !=null && sourcePath.StartsWith(".")) { sourcePath = sourcePath.Substring(1); }
if (targetPath.StartsWith(".")) { targetPath = targetPath.Substring(1); }
var targetTokens = targetPath.Split('.');
var remainingTargetPath = string.Join(".", targetTokens, 0, targetTokens.Length - 1);
var isArray = remainingTargetPath.Contains(ArrayPattern);
var remainingTargetTokens = remainingTargetPath.Split(ArrayPattern.ToCharArray());
//var value = sourceToken.SelectToken(sourcePath);
// 抵达路径顶点
if (targetTokens.Length == 1)
{
targetObject.Add(targetTokens[0], value);
return;
}
// 处理数组类型的映射
if (isArray)
{
if (value is JValue) {
// 将固定数据给数组中的第一个对象
var newItem = (targetObject[targetTokens[0]] ?? new JObject()) as JObject;
CreateJObjectFromString(newItem, targetPath, (JValue)value,1,expression);
targetObject[targetTokens[0]] = newItem;
}
//if (value is JArray)
//{
// string[] childPath = sourcePath.Split(ArrayPattern.ToCharArray());
// string[] destPath = targetPath.Split(ArrayPattern.ToCharArray());
// string arrayKey = targetTokens[0].Split(ArrayPattern.ToCharArray())[0];
// var newItem = (targetObject[arrayKey] ?? new JArray()) as JArray;
// //CreateJObjectFromString(newItem, targetPath, null,0);
// foreach (var item in ((JArray)value).Children())
// {
// var childItem = new JObject();
// ParseAndMapField(item.SelectToken(childPath[2].Substring(1)), childItem, childPath[2], destPath[2]); // 递归处理嵌套路径
// newItem.Add(childItem);
// }
// targetObject[arrayKey] = newItem;
//}
}
else if (targetTokens.Length > 1) {
// 对象层级
string nameKey = targetTokens[0];
int index = 1; //不包含根节点
if (nameKey.Contains("[]"))
{
nameKey = nameKey.Substring(0, nameKey.Length - 2);
index = 0;
}
var newItem = (targetObject[nameKey] ?? new JObject()) as JObject;
CreateJObjectFromString(newItem,targetPath,(JValue)value, index, expression);
targetObject[nameKey] = newItem;
}
else // 普通嵌套映射
{
var newItem = new JObject();
ParseAndMapField(value, newItem, sourcePath, remainingTargetPath); // 递归处理嵌套路径
targetObject.Add(targetTokens[0], newItem);
}
targetObject.Remove(sourcePath);
}
///
/// 根据层级创建对象
///
///
///
///
///
private JObject CreateJObjectFromString(JObject current, string input,JToken value,int index = 1,string expression = "")
{
var keys = input.Split('.');
JObject root = current;
for (int i = index; i < keys.Length - 1; i++)
{
if (keys[i].EndsWith("[]"))
{
string actualKey = keys[i].Substring(0, keys[i].Length - 2);
if (current[actualKey] == null)
{
current[actualKey] = new JArray { new JObject() };
}
// 数组的某一条
current = (JObject)((JArray)current[actualKey]).Last; ;
}
else
{
if (current[keys[i]] == null)
{
current[keys[i]] = new JObject();
}
current = (JObject)current[keys[i]];
}
}
if (!string.IsNullOrEmpty(expression)) {
value = GetExpressionValue(expression, value);
}
current[keys[keys.Length - 1]] = value;
return root;
}
private void SetExpression(string method, string key,object value)
{
try
{
Type type = typeof(ExpressionEvaluator);
MethodInfo mi = type.GetMethod(method);
if (mi != null)
{
mi.Invoke(null, new object[] {key,value });
}
}
catch (Exception e)
{ }
}
private string GetExpressionValue(string method,object value)
{
object objRtn = null;
try
{
Type type = typeof(ExpressionEvaluator);
MethodInfo mi = type.GetMethod(method);
if (mi != null)
{
objRtn = mi.Invoke(null, new object[] { value });
}
}
catch (Exception e)
{ }
return objRtn?.ToString();
}
///
/// 保存配置
///
public void Save()
{
jsonConfig = JsonHelper.toJsonString(this.setting);
if(!string.IsNullOrEmpty(jsonConfig) && !string.IsNullOrEmpty(configFile))
{
File.WriteAllText(configFile,jsonConfig);
}
}
}
public class JsonMappingSetting
{
public List Input { set; get; }
public List Output { set; get; }
public ConvertMapping Convert { set; get; }
}
public class FieldMapping
{
public string Source { get; set; }
public string Target { get; set; }
public string Value { get; set; }
public string Expression { set; get; }
public string Name { get; set; }
public List Child { get; set; }
public FieldMapping()
{ }
}
public class ConvertMapping
{
public string Input { set; get; }
public string Output { set; get; }
}
}