在 Go 中使用匿名成员扁平化编组 JSON 结构

2023-11-21

给出以下代码:(转载于此处play.golang.org.)

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    Id   int    `json:"id"`
    Name string `json:"name"`
}

type Session struct {
    Id     int `json:"id"`
    UserId int `json:"userId"`
}

type Anything interface{}

type Hateoas struct {
    Anything
    Links map[string]string `json:"_links"`
}

func MarshalHateoas(subject interface{}) ([]byte, error) {
    h := &Hateoas{subject, make(map[string]string)}
    switch s := subject.(type) {
    case *User:
        h.Links["self"] = fmt.Sprintf("http://user/%d", s.Id)
    case *Session:
        h.Links["self"] = fmt.Sprintf("http://session/%d", s.Id)
    }
    return json.MarshalIndent(h, "", "    ")
}

func main() {
    u := &User{123, "James Dean"}
    s := &Session{456, 123}
    json, err := MarshalHateoas(u)
    if err != nil {
        panic(err)
    } else {
        fmt.Println("User JSON:")
        fmt.Println(string(json))
    }
    json, err = MarshalHateoas(s)
    if err != nil {
        panic(err)
    } else {
        fmt.Println("Session JSON:")
        fmt.Println(string(json))
    }
}

我试图让呈现的 JSON 看起来correct就我而言,这意味着:

User JSON:
{
    "id": 123,
    "name": "James Dean",
    "_links": {
        "self": "http://user/123"
    }
}
Session JSON:
{
    "id": 456,
    "userId": 123,
    "_links": {
        "self": "http://session/456"
    }
}

不幸的是,Go 将匿名成员视为真实命名的事物,因此它采用定义的类型(Anything) 并如此命名 JSON:

User JSON:
{
    "Anything": {
        "id": 123,
        "name": "James Dean"
    },
    "_links": {
        "self": "http://user/123"
    }
}
Session JSON:
{
    "Anything": {
        "id": 456,
        "userId": 123
    },
    "_links": {
        "self": "http://session/456"
    }
}

没有关于 JSON 中匿名成员处理的明确文档,来自the docs:

匿名结构体字段通常被编组,就好像它们的内部导出字段是外部结构体中的字段一样,遵循下一段中描述的修改后的常见 Go 可见性规则。具有在其 JSON 标记中给出的名称的匿名结构字段被视为具有该名称,而不是匿名的。

处理匿名结构体字段是 Go 1.1 中的新功能。在 Go 1.1 之前,匿名结构体字段被忽略。要强制忽略当前版本和早期版本中的匿名结构字段,请为该字段指定 JSON 标记“-”。

这并不清楚是否有办法进行平坦化,或者向编组者暗示我正在尝试做什么。

我确信,由于存在特殊情况,可能存在具有特殊含义的魔术名称,可以在 XML 编组器中重命名 XML 文档的根元素。

在这种情况下,我也没有以任何方式附加到代码,我的用例是有一个接受的函数interface{}, *http.Request, http.ResponseWriter并通过线路写回 HATEOAS 文档,切换传递的类型,以推断哪些链接写回 JSON。 (从而访问请求、请求主机、端口、方案等,以及类型本身以推断 URL 和已知字段等)


工作游乐场链接:http://play.golang.org/p/_r-bQIw347

其要点是这样的;通过使用 Reflect 包,我们循环遍历我们希望序列化的结构体字段并将它们映射到map[string]interface{}我们现在可以保留原始结构的平面结构,而无需引入新字段。

买者自负,可能应该针对此代码中的某些假设进行多次检查。例如,它假设MarshalHateoas始终接收指向值的指针。

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

type User struct {
    Id   int    `json:"id"`
    Name string `json:"name"`
}

type Session struct {
    Id     int `json:"id"`
    UserId int `json:"userId"`
}

func MarshalHateoas(subject interface{}) ([]byte, error) {
    links := make(map[string]string)
    out := make(map[string]interface{})
    subjectValue := reflect.Indirect(reflect.ValueOf(subject))
    subjectType := subjectValue.Type()
    for i := 0; i < subjectType.NumField(); i++ {
        field := subjectType.Field(i)
        name := subjectType.Field(i).Name
        out[field.Tag.Get("json")] = subjectValue.FieldByName(name).Interface()
    }
    switch s := subject.(type) {
    case *User:
        links["self"] = fmt.Sprintf("http://user/%d", s.Id)
    case *Session:
        links["self"] = fmt.Sprintf("http://session/%d", s.Id)
    }
    out["_links"] = links
    return json.MarshalIndent(out, "", "    ")
}
func main() {
    u := &User{123, "James Dean"}
    s := &Session{456, 123}
    json, err := MarshalHateoas(u)
    if err != nil {
        panic(err)
    } else {
        fmt.Println("User JSON:")
        fmt.Println(string(json))
    }
    json, err = MarshalHateoas(s)
    if err != nil {
        panic(err)
    } else {
        fmt.Println("Session JSON:")
        fmt.Println(string(json))
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Go 中使用匿名成员扁平化编组 JSON 结构 的相关文章

  • CURL 相当于使用 VBA 的 POST JSON 数据

    我知道这与之前提出的一些问题类似 但有些东西仍然对我不起作用 如何执行以下命令 curl X POST data statements json H Content Type application json user username p
  • 如何对数组的数组进行 JSON_MODIFY?

    我的结构看起来像这样 Declare layout NVARCHAR MAX N Sections SectionName Section1 SectionOrder 1 Renders RenderName Render1 RenderO
  • Vue: vue-i18n: 无法翻译 keypath 的值,使用 keypath 的值作为默认值

    我正在使用 Vue 我想展示三种语言 英语 他加禄语和宿务语 现在我有错误 无法转换键路径 NavbarMobile home 的值 使用 keypath 的值作为默认值 我通过 console log this i18n locale 检
  • 使用 catch all 字典属性将 json 序列化为对象

    我想使用 JSON net 反序列化为对象 但将未映射的属性放入字典属性中 是否可以 例如给定 json one 1 two 2 three 3 和 C 类 public class Mapped public int One get se
  • Web API 2.0 使用 pascalcase 模型接收驼峰式命名的 JSON 数据

    我正在尝试对我的 Web API 进行 PUT 调用 我在 WebApiConfig cs 中设置了以下内容 以处理以驼峰形式将数据发送回我的 Web 项目 config Formatters JsonFormatter Serialize
  • 返回视图作为 JSON 对象的一部分

    我有一个应用程序只加载一次完整视图 我这样做的原因并不重要 重要的是 其余内容只会以部分视图的形式返回 除了一些内容之外 我还有一些 JSON 对象 我想通过每个 AJAX 请求在服务器之间来回传递 有没有办法返回一个 JSON 对象 并将
  • 使用 System.Text.Json 序列化记录成员

    我在记录中使用自我引用成员 如下所示 type Payload Id Guid member x DerivedProperty Derived Property using id x Id NewtonSoft Json会序列化这个 但是
  • 有没有办法扩展 angular.json 中的配置?

    在构建 Angular 6 应用程序时 我需要同时指定两件事 如果是生产或开发版本 我正在使用的区域设置 In my angular json I have build configurations production fileRepla
  • 检索 Steam 市场上物品的价格历史记录

    关于 Steam 市场上的物品 我想知道是否有办法检索某物品在一段时间内的价格历史记录 我知道 Steam 为想要将市场特定数据集成到自己网站中的开发人员提供了一个特殊的 api 但我还没有找到任何有关以 json 形式检索商品价格历史记录
  • Bug 组合:jQuery 1.4、ajax/json、Firebug Lite 和 IE 8

    我刚刚得出结论 无论我如何尝试 jQuery 的 ajax 调用都无法在 IE 8 中处理 JSON 数据 我发现我可以使用 jQuery 1 3 2 库 这解决了问题 但 1 4 根本无法处理 JSON ajax 请求 即使返回的 JSO
  • 将 RequestBody json 转换为对象 - Spring Boot

    我是 java 开发的初学者 但之前有 PHP 和 Python 等编程语言的经验 对于如何进行 Spring Boot 的开发几乎没有什么困惑 我正在开发一个rest API 它有以下请求 key value key1 value1 pl
  • 清理 MongoDB 的输入

    我正在为 MongoDB 数据库程序编写 REST 接口 并尝试实现搜索功能 我想公开整个 MongoDB 接口 我确实有两个问题 但它们是相关的 所以我将它们放在一篇文章中 使用 Python json 模块解码不受信任的 JSON 是否
  • 类型错误:JSON 对象必须是 str,而不是“字节”

    我有以下非常基本的代码会抛出 TypeError the JSON object must be str not bytes import requests import json url my url user my user pwd m
  • 将 Java pojo 转换为 json 字符串

    我有以下java类 public class TabularDescriptor extends ReportDescriptor private String generatorClass private String targetCla
  • 使用 NSJSONSerialization 解析 JSON

    对此进行了太多讨论 但我不知道如何解决我的问题 这是我从 WorldWeatherOnline 获取的 JSON 数据 JSON 有效 但我不知道如何解析它 这是我的代码 后面是 JSON 请帮忙 NSError errorInfo NSD
  • Go 指针 - 通过指针将值附加到切片

    我有一个 struct ProductData 及其实例 p 它有一个切片属性 type ProductInfo struct TopAttributes map string interface 我想设置 TopAttributes 如下
  • 管理多租户 ArangoDB 连接

    我使用 ArangoDB Go 使用 go driver 并且需要实现多租户 这意味着每个客户都将在单独的数据库中拥有他的数据 我想要弄清楚的是如何使这种多租户发挥作用 我知道为每个请求创建一个新的数据库连接是不可持续的 这意味着我必须维护
  • 解析错误:第 2 行第 0 列的数字文字无效

    我正在尝试读取一个大的 json 数据结构 我收到消息 解析错误 第 2 行第 0 列的数字文字无效 我正在使用的命令是下一个 n rules echo rulebase list jq total 该文件在第一层次结构中具有一个变量 该变
  • Rspec 控制器测试,传递 JSON 参数

    我试图实现以下目标 在 RSpec 控制器测试中创建 POST json 请求 并向其传递参数 这是我的代码 it returns access token do post login email bla password bla1 for
  • 共享 GOPATH 的良好做法是什么?

    我刚刚开始学习 Go 并阅读现有代码以了解 其他人是如何做的 在这样做时 go 工作空间 的使用 特别是当它与项目的依赖项相关时 似乎无处不在 在处理各种 Go 项目时 使用单个或多个 Go 工作区 即 GOPATH 的定义 的常见最佳实践

随机推荐

  • ShadowRoot.getSelection()?

    我有一个丰富的编辑器 我正在将其重写为 lit element 自定义元素 我使用 Firefox 最新 进行测试 我试图在自定义元素的 ShadowDom 中选择内容可编辑元素 在方法中 在 Firefox 调试器中 this shado
  • 如何使用 Python 将换行符写入 csv 中“\n”?

    我需要重新定义以下代码 以便行数据中的任何换行符 将显示为空行 显示为 n 书面文件中 然而 n 需要在每行之后写入以显示为空行 显然 每一行都需要编码为 utf 8 以避免错误 with open csvfile csv w as csv
  • C# 序列化和反序列化json到txt文件

    我在用着牛顿软件用于在我的 wpf 应用程序中处理 json 我有一个可以保存到txt 文件的客户 不涉及数据库 我这样做是这样的 public int store string reservation JObject customer n
  • 为什么我们使用数组而不是其他数据结构?

    在我编程时 我还没有看到数组比其他形式更适合存储信息的实例 我确实认为编程语言中添加的 功能 已经对此进行了改进 并由此取代了它们 我现在发现它们并没有被取代 而是被赋予了新的生命 可以这么说 那么 基本上 使用数组有什么意义呢 这并不是说
  • C++ 中宏相对于内联的优势

    我们知道内联是有利的 因为它们由编译器检查 并且与宏相比 作为参数传递时相同的操作 如 x 不会计算多次 但在一次采访中 有人问我在 C 中宏更适合内联的具体优点或情况 有谁知道答案或者可以思考这个问题 我唯一能想到的是 您可以使用宏来完成
  • 获取 iPhone 的物理屏幕尺寸(以英寸为单位)

    如何以编程方式获取以英寸为单位的屏幕尺寸 例如 iPhone 4 3 5 英寸 我找到了一种通过检测 iPhone iPad 型号来做到这一点的方法 但硬编码不是我想要的 所以我不看这样的东西 Swift 4 屏幕版本 let scale
  • mongodb c# API V2:ReplaceOne 和 FindOneAndReplace 之间的区别

    查看 mongodb 文档 我读到 FindOneAndReplace 将是一个原子操作 但我不明白的是为什么 ReplaceOne 不是原子的 如果存在差异 为什么还要使用 ReplaceOne 该文档揭示了一个不同的方法签名 替换一个
  • 读取文件直到Python中的特定字符

    我目前正在开发一个应用程序 该应用程序需要从文件中读取所有输入 直到遇到某个字符 通过使用代码 file open Questions txt r c file readlines c x strip for x in c 每次脱衣相遇 n
  • 从不同的基类重载同名的虚函数。是否可以? [复制]

    这个问题在这里已经有答案了 标题可能令人困惑 假设我们有以下设置 class A public virtual void fn 0 class B public virtual int fn class C public A public
  • R 创建包含每行最大值的列名的列

    我和这个问题有同样的要求 对于每一行返回最大值的列名 但是 我需要包含每行最大值的所有列的名称 如果我每行有两个相同的最大值 上面链接中提供的所有解决方案都会出现问题 df lt data frame V1 c 2 8 1 5 6 V2 c
  • 如何使用 c-ares 将 IP 解析为主机?

    这就是我到目前为止所做的 它可以编译 但当我尝试运行它时会出现段错误 include
  • 如何处理您想要扩展的密封在 .NET 库中的类?

    我正在阅读有关如何处理想要扩展 NET Framework 库中的密封类的问题的文章 这通常是一项常见且有用的任务 因此我开始思考 在这种情况下 有哪些解决方案 我相信在我读过的文章中演示了一种扩展密封类的 方法 但我现在不记得了 它不是扩
  • 如何获取通用 Windows 批处理文件时间戳

    我在 Windows 批处理文件中生成时间戳时遇到问题 因为我在不同的 Windows 版本上得到不同的日期格式 我的机器 gt echo date gt Tue 11 17 2009 友机 gt echo date gt 11 17 20
  • 如何使用 .bat 文件从 PATH 环境变量中删除特定标记?

    我正在编写卸载脚本 因此我想 撤消 安装对系统所做的修改 为了实现这个目标 我想解析PATH变量 并删除安装添加到的任何值PATH 为此 我开发了以下伪代码 保存内容PATH到临时变量 拆分PATH转换为令牌 使用 字符作为分隔符 并循环遍
  • 将表转换为分层字典?

    我有一个表格 A1 B1 C1 value A1 B1 C1 value A1 B1 C2 value A1 B2 C1 value A1 B2 C1 value A1 B2 C2 value A1 B2 C2 value A2 B1 C1
  • 瘦服务器:将 Rails 应用程序日志输出到控制台,如“rails s”那样

    我需要跑thin start or thin ssl start在我的 Rails 应用程序的根目录中 并查看输出到控制台的应用程序日志 类似于rails s does In config ru文件 位于应用程序的根目录 在该行之前添加以下
  • 授予 Node.js 访问证书/私钥的权限

    我正在尝试在我的 Node js 应用程序上使用 HTTPS 就像它已针对其他任何内容启用一样 我已经安装了密钥和证书 但我得到了Error EACCES permission denied当我试图在应用程序上指向它们时 密钥和证书都位于以
  • 是否可以保证 memset 将结构中的填充位清零?

    一般来说 根据 C 标准 是否可以保证带有 0 的 memset 会将 C 结构中的填充位清零 海湾合作委员会呢 例如 类似 struct MyStruct unsigned char member1 unsigned int member
  • 在 viewpager 中显示 Youtube 视频

    我想设置YouTube内的视频ViewPager 为此我设置了FrameLayout在适配器中 我在其中设置了 YoutubeVideoFragment 如下所示 我的 ViewPager 适配器 import android app Ac
  • 在 Go 中使用匿名成员扁平化编组 JSON 结构

    给出以下代码 转载于此处play golang org package main import encoding json fmt type User struct Id int json id Name string json name