簡體   English   中英

將 JSON 駝峰案例轉換為蛇案例(反之亦然)並字符串化數值

[英]Convert JSON camel case to snake case (and vice versa) and stringify numeric values

我必須向 Web REST 服務發送和接收 JSON 對象。 這些對象由一個 DLL 生成,該 DLL 將大寫字母(“PropertyName”)中的屬性名稱序列化,並且 Web 服務需要蛇形大小寫(“property_name”)。 另外,DLL 將數值序列化為浮點數,但 REST API 需要所有字符串。 處理對象后,REST 服務返回蛇形大小寫 JSON。

JSON 很復雜並且包含嵌套的數組和對象。 在從 REST 字符串轉換回來時,我可以跳過數字字符串的去字符串化,但我仍然必須將屬性名稱重新轉換為大寫字母。

我正在考慮使用 Newtonsoft Json 庫編寫一個輔助類,但它看起來比我預期的要棘手。 轉換器應接受 JSON 並返回 JSON。

例子:

{
    "FirstObject": {
        "NestedObject": {
            "AttributeString": "ok",
            "AttributeNumeric": 123.45
        },
        "OtherObject": [{
            "ArrayVal": 100
        }, {
            "ArrayVal": 200
        }]
    }
}

應該成為

{
    "first_object": {
        "nested_object": {
            "attribute_string": "ok",
            "attribute_numeric": "123.45"
        },
        "other_object": [{
            "array_val": "100"
        }, {
            "array_val": "200"
        }]
    }
}

我看到 Json.Net 庫有SnakeCaseNamingStrategyCamelCaseNamingStrategy類,所以想法是使用JsonTextReader來解析輸入,更改屬性名稱的命名約定,將數值設置為字符串,並使用JsonTextWriter編寫修改后的標記。

我找不到有關如何執行此操作的任何示例。

做你想做的最簡單的方法是使用一組與你的 JSON 匹配的模型類。 (您可以通過將 JSON 的完整示例復制到剪貼板,然后使用Edit -> Paste Special -> Paste JSON as Classes函數在 Visual Studio 中生成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);
    }
}

要使用它,您只需要為您的輸入 JSON 設置一個TextReader為輸出設置一個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);
}

現在,對於回程,有一點問題。 NamingStrategy只在一個方向上起作用; 它不提供反轉轉換的工具。 這意味着 Newtonsoft 提供的所有NamingStrategy類都無法按照您想要的方式將蛇形大小寫轉換回駝色大寫字母。 CamelCaseNamingStrategy將不起作用,因為它不希望以蛇形字母開頭(它想要大駝峰字母),而且它的輸出無論如何都不是大駝峰字母。 DefaultNamingStrategy也不會工作,因為它實際上根本不做任何轉換——它只是一個傳遞。

解決方案是制作您自己的自定義NamingStrategy 幸運的是,這並不難做到。 只需從基礎NamingStrategy類派生並實現抽象ResolvePropertyName方法:

// 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM