首页 > 解决方案 > 有没有办法在不改变格式的情况下修改 JSON?

问题描述

使用Newtonsoft.Json,您可以选择如何使用 .json 的Formatting枚举和属性来格式化 JSON JsonTextWriter。但是如果我从一个已经以某种方式格式化的 JSON 字符串开始并且我想修改它,有没有办法确保它保留它的格式?

我可以想到一些探索的途径:

  1. 当前是否有任何 JSON 库可以在不反序列化的情况下修改 JSON 字符串?
  2. 反序列化 JSON 字符串时,有没有办法检测字符串的格式,以便在重新序列化时可以应用相同的格式?
  3. 是否有一个函数将反序列化JObject与它来自的 JSON 字符串相结合,以便将对象的更改应用于旧字符串之上,而不是用于构建新字符串?

问题示例:

var obj = JObject.Parse(json);
obj["foo"] = "bar";

Console.WriteLine(obj.ToString(Formatting.Indented));
// {
//   "baz": "qux",
//   "foo": "bar"
// }

Console.WriteLine(obj.ToString(Formatting.None));
// {"baz":"qux","foo":"bar"}

// Not knowing how the input was formatted,
// how can I know what options to use?

解决方案可能是什么样的:

var format = JsonConvert.GetFormat(json); // No such method?
var obj = JObject.Parse(json);
obj["foo"] = "bar";

Console.WriteLine(obj.ToString(format));

(我知道有更多的方式来格式化 JSON,而不仅仅是选择Indentedor None,但为了清楚起见,我让示例保持简单。)

标签: c#jsonjson.netformattingindentation

解决方案


我会争辩说:这可能是徒劳的追求。

尽管它是人类可读的,但它很少被人类阅读。事实上,我更担心不小心将重要的东西解析进出有效对象。

但是,为了在 Newtonsoft 中获得一点乐趣,这适用于在原件缩进时没有缩进的格式。

var person = new Person()
    {
        Name = "John",
        Colors = new List<string>() {"Red", "Blue","Green"}
    };

    var rawJson = Newtonsoft.Json.JsonConvert.SerializeObject(person, Formatting.Indented);     
    var newJson = Newtonsoft.Json.JsonConvert.SerializeObject(person, Formatting.None);

    var settings =  new Newtonsoft.Json.JsonSerializerSettings();
    settings.Formatting = (Formatting)(newJson.Length <= rawJson.Length ? 1 : 0);       

    var finalJson = JsonConvert.SerializeObject(person, settings);

如果我们只关心 Newtonsoft,并且是否缩进,我相信这在以下前提下就足够了:

  1. 我们从客户端控制格式的变化
  2. 如果缩小,格式更改为 Newtonsoft 的默认值
  3. 假设它不能增长
  4. 如果转换使字符串保持相同的长度,则没有任何变化

当然,问题案例的出现如下:

  1. 收到的 JSON 包含额外的字符:"First Name:",这在 Json 中有效,但在 Class 属性名称中无效,因此您可能需要担心一个属性。
  2. JSON 仍然是一个字符串,可能会出现各种奇怪的东西,因此以任何程度的确定性验证它都可能成为一场傻瓜比赛(建立一个更好的傻瓜)

事实上,如果某些工具的目的是将数据呈现给人类:选择最易读的格式(对我来说是缩进的)并始终显示它。

如果设计通常是机器,那么对于最小的有效载荷使用 none。我认为几乎所有习惯使用 JSON 的开发人员都希望将最小化的 JSON 作为有效负载。


推荐阅读