C# JSON属性名称作为属性的整个JSON路径
我希望每个JSON属性名都代表它的路径C# JSON属性名称作为属性的整个JSON路径,c#,json,.net,json.net,C#,Json,.net,Json.net,我希望每个JSON属性名都代表它的路径 public class Person { public string FirstName { get; set; } public string LastName { get; set; } public Address Address { get; set; } } public class Address { public string Street { get; set; } public string S
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string Street { get; set; }
public string StreetNumber { get; set; }
}
使用Newtonsoft.Json,我当前获得以下Json:
{
"firstName":"Homer",
"lastName":"Simpson",
"address":{
"street":"Evergreen Terrace",
"streetNumber":"742"
}
}
是否可以改为获取此JSON:
{
"person.firstName":"Homer",
"person.lastName":"Simpson",
"person.address":{
"person.address.street":"Evergreen Terrace",
"person.address.streetNumber":"742"
}
}
你不能那样做,因为这是模棱两可的。如何反序列化此文件 在C#中,它可以解释为
公共类人物
{
公共字符串Person.firstName{get;set;}
公共字符串Person.LastName{get;set;}
公共广播人员.地址{get;set;}
}
它的格式无效,因此您的文件必须导致异常或编译错误
在浏览器上使用
JSON.parse()
方法尝试此操作,您将得到一个具有此结构的对象(属性名称带有点)。此格式无效。但是:
样品
Json.NET不会使用JSONPATH作为开箱即用的属性名来序列化对象,因为它是基于约定的序列化程序。因此,它将以在序列化图中遇到的相同方式序列化某些类型的所有实例。相反,对于遇到的每个实例,您需要一个稍微不同的契约,该契约反映了图中实例的路径 那么,获取所需JSON的选项是什么 首先,您可以使用
公共静态无效重命名(此JToken标记,字符串newName)
扩展方法将其从序列化到后处理:
后来:
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
};
Func<string, int, string, string> map = (name, depth, parentPath) => "person." + parentPath;
using var textWriter = new StringWriter();
using (var jsonWriter = new NameRemappingJsonWriter(textWriter, map) { Formatting = Formatting.Indented })
{
JsonSerializer.CreateDefault(settings).Serialize(jsonWriter, person);
}
var json = textWriter.ToString();
var设置=新的JsonSerializerSettings
{
ContractResolver=新的CamelCasePropertyNamesContractResolver(),
};
Func map=(名称、深度、父路径)=>“个人”+parentPath;
使用var textWriter=new StringWriter();
使用(var jsonWriter=newnameremappingjsonwriter(textWriter,map){Formatting=Formatting.Indented})
{
CreateDefault(设置).Serialize(jsonWriter,person);
}
var json=textWriter.ToString();
请注意,为了实现这一点,我必须调用基类JsonWriter.WritePropertyName()
方法的基,该方法略显粗略和简单
Demo fiddle#2.之后需要对JSON进行后处理。Json.NET是一个基于契约的序列化程序,因此,如果图中出现多个
Address
对象,它将使用相同的契约以相同的方式序列化它们。对于图形中出现的每个Address
,您都需要不同的合同(因为属性名称不同)。序列化到JObject
,然后修复属性名似乎是一条可行之路。这回答了你的问题吗?
var p = new Person() { Address = new Address() { Street = "1", StreetNumber = "2" }, FirstName = "a", LastName = "b" };
var x = _getCustomJsonFormat(p);
var person = new Person
{
// Initialize your Person as required
};
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
};
var jObject = JObject.FromObject(person, JsonSerializer.CreateDefault(settings));
foreach (var item in jObject.Descendants().OfType<JProperty>().Select(p => (Property: p, p.Path)).ToList())
{
// The Rename extension method from https://stackoverflow.com/a/47269811/3744182
item.Property.Rename("person." + item.Path);
}
var json = jObject.ToString();
public class NameRemappingJsonWriter : JsonTextWriter
{
readonly Action<string> jsonWriterWritePropertyName;
readonly Func<string, int, string, string> map;
public NameRemappingJsonWriter(TextWriter textWriter, Func<string, int, string, string> map) : base(textWriter)
{
this.map = map ?? throw new ArgumentNullException(nameof(map));
//Method to call a base-of-base-class method taken from this answer https://stackoverflow.com/a/32562464
//By https://stackoverflow.com/users/5311735/evk
//To https://stackoverflow.com/questions/2323401/how-to-call-base-base-method
var ptr = typeof(JsonWriter).GetMethod("WritePropertyName", new[] { typeof(string) }).MethodHandle.GetFunctionPointer();
jsonWriterWritePropertyName = (Action<string>)Activator.CreateInstance(typeof(Action<string>), this, ptr);
}
public override void WritePropertyName(string name) => WritePropertyName(name, true);
public override void WritePropertyName(string name, bool escape)
{
jsonWriterWritePropertyName(name);
WriteRaw(JsonConvert.ToString(map(name, Top, Path)));
WriteRaw(":");
}
}
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
};
Func<string, int, string, string> map = (name, depth, parentPath) => "person." + parentPath;
using var textWriter = new StringWriter();
using (var jsonWriter = new NameRemappingJsonWriter(textWriter, map) { Formatting = Formatting.Indented })
{
JsonSerializer.CreateDefault(settings).Serialize(jsonWriter, person);
}
var json = textWriter.ToString();