将 JSON 驼峰式大小写转换为蛇形大小写(反之亦然)并将数值字符串化

2023-12-08

我必须向 Web REST 服务发送和接收 JSON 对象。这些对象由 DLL 生成,该 DLL 将属性名称序列化为大驼峰式命名法(“PropertyName”),而 Web 服务需要蛇形命名法(“property_name”)。 另外,DLL 将数值序列化为浮点数,但 REST API 需要所有字符串。 处理对象后,REST 服务返回蛇形 JSON。

JSON 很复杂,包含嵌套数组和对象。从 REST 字符串转换回来时,我可以跳过数字字符串的去字符串化,但我仍然必须将属性名称重新转换为大驼峰式大小写。

我正在考虑使用 Newtonsoft Json 库编写一个帮助器类,但它看起来比我预期的要棘手。转换器应接受 JSON 并返回 JSON。

Example:

{
    "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 库有SnakeCaseNamingStrategy and CamelCaseNamingStrategy类,所以这个想法是使用JsonTextReader要解析输入,请更改属性名称的命名约定,将数值设置为字符串,然后使用JsonTextWriter.

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


完成您想要的操作的最简单方法是使用一组与您的 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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将 JSON 驼峰式大小写转换为蛇形大小写(反之亦然)并将数值字符串化 的相关文章

  • 以文化中立的方式将字符串拆分为单词

    我提出了下面的方法 旨在将可变长度的文本拆分为单词数组 以进行进一步的全文索引处理 删除停止词 然后进行词干分析 结果似乎不错 但我想听听关于这种实现对于不同语言的文本的可靠性的意见 您会建议使用正则表达式来代替吗 请注意 我选择不使用 S
  • WCF RIA 服务 - 加载多个实体

    我正在寻找一种模式来解决以下问题 我认为这很常见 我正在使用 WCF RIA 服务在初始加载时将多个实体返回给客户端 我希望两个实体异步加载 以免锁定 UI 并且我想利用 RIA 服务来执行此操作 我的解决方案如下 似乎有效 这种方法会遇到
  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 动态加载程序集的应用程序配置

    我正在尝试将模块动态加载到我的应用程序中 但我想为每个模块指定单独的 app config 文件 假设我的主应用程序有以下 app config 设置
  • jQuery AJAX 请求在 IE8 中失败,并显示消息“错误:调用 open 方法之前无法调用此方法。”

    我正在使用 jQuery 1 4 2 并尝试执行一个简单的 AJAX 请求 目标 URL 返回一个 JSON 字符串 我使用 jslint 对其进行了验证 该请求在 Firefox 和 Chrome 中有效 但不想在 IE8 中工作 我无法
  • 在 Windows 窗体中保存带有 Alpha 通道的单色位图会保存不同(错误)的颜色

    在 C NET 2 0 Windows 窗体 Visual Studio Express 2010 中 我保存由相同颜色组成的图像 Bitmap bitmap new Bitmap width height PixelFormat Form
  • 关于 C++ 转换:参数 1 从“[some_class]”到“[some_class]&”没有已知的转换

    我正在研究 C 并且遇到了一个错误 我不知道确切的原因 我已经找到了解决方案 但仍然想知道原因 class Base public void something Base b int main Base b b something Base
  • 堆栈溢出:堆栈空间中重复的临时分配?

    struct MemBlock char mem 1024 MemBlock operator const MemBlock b const return MemBlock global void foo int step 0 if ste
  • 创建链表而不将节点声明为指针

    我已经在谷歌和一些教科书上搜索了很长一段时间 我似乎无法理解为什么在构建链表时 节点需要是指针 例如 如果我有一个节点定义为 typedef struct Node int value struct Node next Node 为什么为了
  • WCF 中 SOAP 消息的数字签名

    我在 4 0 中有一个 WCF 服务 我需要向 SOAP 响应添加数字签名 我不太确定实际上应该如何完成 我相信响应应该类似于下面的链接中显示的内容 https spaces internet2 edu display ISWG Signe
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • while 循环中的 scanf

    在这段代码中 scanf只工作一次 我究竟做错了什么 include
  • 如何序列化/反序列化自定义数据集

    我有一个 winforms 应用程序 它使用强类型的自定义数据集来保存数据进行处理 它由数据库中的数据填充 我有一个用户控件 它接受任何自定义数据集并在数据网格中显示内容 这用于测试和调试 为了使控件可重用 我将自定义数据集视为普通的 Sy
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • Windows 窗体:如果文本太长,请添加新行到标签

    我正在使用 C 有时 从网络服务返回的文本 我在标签中显示 太长 并且会在表单边缘被截断 如果标签不适合表单 是否有一种简单的方法可以在标签中添加换行符 Thanks 如果您将标签设置为autosize 它会随着您输入的任何文本自动增长 为
  • GitHub Actions:如何将 toJSON() 结果传递给 shell 命令

    因此 我正在与 Github Actions 合作进行端到端测试 我正在查看的设置是让一项作业检索要测试的 url 列表 而我的第二项作业使用该列表创建一个矩阵并测试所有这些 我的问题是 当我实际运行测试脚本时 必须从命令行完成 因为我使用
  • 如何从两个不同的项目中获取文件夹的相对路径

    我有两个项目和一个共享库 用于从此文件夹加载图像 C MainProject Project1 Images 项目1的文件夹 C MainProject Project1 Files Bin x86 Debug 其中有project1 ex
  • C# 成员变量继承

    我对 C 有点陌生 但我在编程方面有相当广泛的背景 我想做的事情 为游戏定义不同的 MapTiles 我已经像这样定义了 MapTile 基类 public class MapTile public Texture2D texture pu
  • C++ 中类级 new 删除运算符的线程安全

    我在我的一门课程中重新实现了新 删除运算符 现在我正在使我的代码成为多线程 并想了解这些运算符是否也需要线程安全 我在某处读到 Visual Studio 中默认的 new delete 运算符是线程安全的 但这对于我的类的自定义 new
  • 对来自流读取器的过滤数据执行小计

    编辑问题未得到解答 我有一个基于 1 个标准的过滤输出 前 3 个数字是 110 210 或 310 给出 3 个不同的组 从流阅读器控制台 问题已编辑 因为第一个答案是我给出的具体示例的字面解决方案 我使用的实际字符串长度为 450 个

随机推荐

  • 如何在 ASP.NET Web API 内存测试中添加客户端证书?

    我想使用内存测试我的 Web API 服务HttpServer 当前的设置如下所示 var httpConfig CreateTestHttpConfiguration var server new HttpServer httpConfi
  • 我可以在 iOS AppStore 上显示 2 个或更多开发者名称吗?

    如果有2个或更多开发者为AppStore开发了应用程序 他们的名字如何同时显示在应用程序下方 另外 他们都需要有一个开发者帐户吗 还是一个就足够了 您需要一份单一的付费开发者协议 只有与 Apple 签订开发者分销协议的实体 个人或公司 的
  • 将 Canvas 元素转换为 Image 并存储在数据库中

    I want to store the Image into my Server side Database Once the user draw using canvas and hit a Submit button Canvas El
  • Android Listview 行重复项

    我有一个列表 在我从共享首选项中获得的特定数字 位置 上应该显示图像视图 指示当前正在播放的歌曲 但我得到了位置 但该项目也显示在其他行上 当我滚动列表时出现问题 当我退出另一项活动时会发生这种情况 并且在我的简历中我会这样 Overrid
  • 与 Azure Postgres 的连接时间较长

    我有 Azure Database for PostgreSQL 服务 PaaS 当我尝试查询它时psql然后甚至简单SELECT从一张表查询大约需要 1 5 秒 当我在 postgres 控制台中时 没有问题 查询执行时间不到 100 毫
  • 使用ggplot2,我可以在轴中插入断点吗?

    我想制作一个条形图 其中一个值比所有其他值大得多 有没有办法让y轴不连续 我的数据如下 df lt data frame a c 1 2 3 500 b c a1 a2 a3 a4 p lt ggplot data df aes x b y
  • 检查 PHP 多维数组中是否存在数组值

    我有以下多维数组 Array 0 gt Array id gt 1 name gt Jonah points gt 27 1 gt Array id gt 2 name gt Mark points gt 34 我目前正在使用foreach
  • 在 C++ 中使用 getline 忽略空格[重复]

    这个问题在这里已经有答案了 嘿 我正在尝试编写一个程序 该程序将接受人们的新任务 将其添加到堆栈中 能够显示任务 能够将该堆栈保存到文本文件中 然后读取文本文件 当我尝试接受用户的输入时 问题就出现了 每当您输入带有空格的字符串时 选择要执
  • 创建自定义 tomcat 会话管理器而不将 jar 放入 CATALINA_HOME 目录?

    我正在为 Tomcat 开发一个自定义会话管理器 并且我让它工作时有一个警告 我必须将 jar 以及所有相关的 jar 放在 CATALINA HOME lib 目录中 否则我会得到一个 noclassdef 发现异常 即使类位于 WEB
  • PHPExcel 创建“不可读的内容”

    我尝试了大约 1000 种不同的方法来解决这个问题 如果其他人能够发现问题 我们将不胜感激 我有使用 PHPExcel 的代码 可以生成多个 Excel 工作表并将它们保存到磁盘 使用 MS Excel 2010 打开第二个文件及以后的所有
  • Images.xcassets 为 iPhone 6 拍摄了错误的图像?

    我已经为 2x Retina 4 和 3x 设置了三个图像 当我运行该应用程序时 我得到以下结果 iPhone 4s 推特图像 iPhone 5 谷歌图片 iPhone 6 脸书图片 iPhone 6 推特图像 一切都很好 但是当我跑在iP
  • 使用 JMESPATH 获取对象上的 JSON 元素的查询

    当我有一个简单的 JSON 时 例如 name Tom age 20 是否有任何 JMESPath 查询可以获取age只有当name is Tom 查询应该得到20与上面的 JSON 一起 但是 如果名字不是Tom like name Bo
  • 为什么在平移和更改相机角度时我的有线球体会变成椭球体?

    我需要沿 z 轴来回平移有线球体 同时更改相机角度 每当我的球体被平移时 它就会慢慢变成椭球体 我实在不明白为什么 在这里您可以看到我认为有错误的代码片段 此外 调整窗口大小时不应更改形状 而只能更改其大小 void init glClea
  • Android 中的全文搜索示例

    我很难理解如何在 Android 上使用全文搜索 FTS 我读过有关 FTS3 和 FTS4 扩展的 SQLite 文档 而且我知道在Android上可以做到 然而 我很难找到任何我能理解的例子 基本数据库模型 一个 SQLite 数据库表
  • iPhone 亮度私有 API 无法正常工作

    我正在尝试设置背光的亮度 但它的表现非常奇怪 我正在使用私有 API id UIApplication共享应用 setBacklightLevel 1 0f 然而 当我调用此命令时 屏幕变暗 并没有像我想象的那样变得 100 亮 我用各种数
  • 匹配除电子邮件地址之外的所有内容的正则表达式

    假设这是输入 这是一个段落 这是一个段落 这是一个段落 这是一个段落 这是一个段落 这是一个段落 这是一个电子邮件地址 电子邮件受保护 我想要一个匹配除电子邮件地址之外的所有内容的正则表达式 我努力了 这会匹配除电子邮件所在的 LINE 之
  • 是否有缺少固定宽度类型 (intXX_t) 的平台?

    C 11 具有固定宽度 2 的补码类型 u int8 t u int16 t etc 然而 这些类型是可选的 有时我需要使用这些类型 因此我的代码可能不太可移植 有没有什么平台 提供 C 11 编译器 目前 哪些类型不存在 是否有任何 通用
  • Android 长按滚动

    我想将长按与滚动 连接 这样用户就不必释放屏幕并开始滚动 我已经实现了手势检测器 final GestureDetector gestureDetector new GestureDetector new GestureDetector S
  • 未找到 Apple-app-site-association

    我正在尝试通过Apple 搜索验证工具 并且我在使用 apple app site association 时遇到问题 由于某种原因 机器人找不到我的文件 但如果你打开 URL 它就在那里 这不是格式问题 因为甚至找不到该文件 我有 htt
  • 将 JSON 驼峰式大小写转换为蛇形大小写(反之亦然)并将数值字符串化

    我必须向 Web REST 服务发送和接收 JSON 对象 这些对象由 DLL 生成 该 DLL 将属性名称序列化为大驼峰式命名法 PropertyName 而 Web 服务需要蛇形命名法 property name 另外 DLL 将数值序