完成您想要的操作的最简单方法是使用一组与您的 JSON 匹配的模型类。 (您可以通过将 JSON 的完整示例复制到剪贴板,然后使用Edit -> Paste Special -> Paste JSON as Classes
函数。)使模型类使用大驼峰式命名法作为属性名称(无论如何,这是 C# 的标准命名约定),并使用字符串代替数字属性。
因此,对于您的示例 JSON,模型类将如下所示:
public class RootObject
{
public FirstObject FirstObject { get; set; }
}
public class FirstObject
{
public NestedObject NestedObject { get; set; }
public List<OtherObject> OtherObject { get; set; }
}
public class NestedObject
{
public string AttributeString { get; set; }
public string AttributeNumeric { get; set; }
}
public class OtherObject
{
public string ArrayVal { get; set; } // using string instead of int here
}
然后,要将大驼峰式 JSON 转换为蛇形式,可以执行以下操作:
var obj = JsonConvert.DeserializeObject<RootObject>(json);
var settings = new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy { ProcessDictionaryKeys = true }
},
Formatting = Formatting.Indented
};
json = JsonConvert.SerializeObject(obj, settings);
原始 JSON 会自然地反序列化为模型,因为属性名称已经匹配。 Json.Net 会根据需要自动将 JSON 中的数值转换为字符串以适合类属性。在序列化方面,SnakeCaseNamingStrategy
将属性名称更改为蛇形命名。数值以字符串形式写出,因为这是在类中声明属性的方式。
要以另一种方式返回,您可以执行以下操作:
obj = JsonConvert.DeserializeObject<RootObject>(json, settings); // same settings as above
json = JsonConvert.SerializeObject(obj, Formatting.Indented);
这里,在反序列化过程中,Json.Net 使用SnakeCaseNamingStrategy
再次将模型属性名称转换为蛇形命名法,以便将它们与 JSON 属性相匹配。数值已经是 JSON 中的字符串,因此不需要转换。在序列化时,我们没有使用任何特殊设置,因此属性名称完全按照声明的方式写出,即大驼峰式大小写。保存数值的字符串属性仍然是字符串(您说这在您的问题中没问题)。
这是一个往返演示:https://dotnetfiddle.net/3Pb1fT
如果您没有可用的模型,仍然可以使用以下方法进行此转换JsonReader
/JsonWriter
您建议的方法,但需要更多的代码将它们粘合在一起并进行转换。这是一个辅助方法,可以完成大部分繁重的工作:
public static void ConvertJson(TextReader textReader, TextWriter textWriter,
NamingStrategy strategy,
Formatting formatting = Formatting.Indented)
{
using (JsonReader reader = new JsonTextReader(textReader))
using (JsonWriter writer = new JsonTextWriter(textWriter))
{
writer.Formatting = formatting;
if (reader.TokenType == JsonToken.None)
{
reader.Read();
ConvertJsonValue(reader, writer, strategy);
}
}
}
private static void ConvertJsonValue(JsonReader reader, JsonWriter writer,
NamingStrategy strategy)
{
if (reader.TokenType == JsonToken.StartObject)
{
writer.WriteStartObject();
while (reader.Read() && reader.TokenType != JsonToken.EndObject)
{
string name = strategy.GetPropertyName((string)reader.Value, false);
writer.WritePropertyName(name);
reader.Read();
ConvertJsonValue(reader, writer, strategy);
}
writer.WriteEndObject();
}
else if (reader.TokenType == JsonToken.StartArray)
{
writer.WriteStartArray();
while (reader.Read() && reader.TokenType != JsonToken.EndArray)
{
ConvertJsonValue(reader, writer, strategy);
}
writer.WriteEndArray();
}
else if (reader.TokenType == JsonToken.Integer)
{
// convert integer values to string
writer.WriteValue(Convert.ToString((long)reader.Value));
}
else if (reader.TokenType == JsonToken.Float)
{
// convert floating point values to string
writer.WriteValue(Convert.ToString((double)reader.Value,
System.Globalization.CultureInfo.InvariantCulture));
}
else // string, bool, date, etc.
{
writer.WriteValue(reader.Value);
}
}
要使用它,您只需设置一个TextReader
对于您的输入 JSON 和TextWriter
为输出,并传入适当的NamingStrategy
您想用于转换。例如,要将原始 JSON 字符串转换为蛇形大小写,您可以这样做:
using (StringReader sr = new StringReader(upperCamelCaseJson))
using (StringWriter sw = new StringWriter())
{
ConvertJson(sr, sw, new SnakeCaseNamingStrategy(), formatting);
string snakeCaseJson = sw.ToString();
...
}
或者,如果 JSON 的源和/或目标是某种类型的流,则可以使用StreamReader
/StreamWriter
反而:
using (StreamReader sr = new StreamReader(inputStream))
using (StreamWriter sw = new StreamWriter(outputStream))
{
ConvertJson(sr, sw, new SnakeCaseNamingStrategy(), formatting);
}
现在,回程时遇到了一些问题。 ANamingStrategy
只在一个方向起作用;它不提供反转转换的工具。这意味着 Newtonsoft 提供的任何NamingStrategy
类可以按照您想要的方式将蛇形大小写转换回大驼峰大小写。这CamelCaseNamingStrategy
不起作用,因为它不希望以蛇形命名法开始(它需要大驼峰命名法),并且它的输出无论如何都不是大驼峰命名法。这DefaultNamingStrategy
也不起作用,因为它实际上根本不做任何转换——它只是一个传递。
解决方案是定制您自己的NamingStrategy
。幸运的是,这并不难做到。只需从基础派生NamingStrategy
类并实现抽象ResolvePropertyName
method:
// This naming strategy converts snake case names to upper camel case (a.k.a. proper case)
public class ProperCaseFromSnakeCaseNamingStrategy : NamingStrategy
{
protected override string ResolvePropertyName(string name)
{
StringBuilder sb = new StringBuilder(name.Length);
for (int i = 0; i < name.Length; i++)
{
char c = name[i];
if (i == 0 || name[i - 1] == '_')
c = char.ToUpper(c);
if (c != '_')
sb.Append(c);
}
return sb.ToString();
}
}
现在您可以将这个新策略传递给ConvertJson
如上所述的方法将蛇形 JSON 转换回大驼峰式。
往返演示:https://dotnetfiddle.net/jt0XKD