为了账号安全,请及时绑定邮箱和手机立即绑定

在不解组的情况下检查 json 数组长度

在不解组的情况下检查 json 数组长度

Go
慕哥9229398 2022-10-24 15:29:47
我有一个请求主体,它是一个 json 对象数组,例如,    {        "data": [            {                "id": "1234",                "someNestedObject": {                    "someBool": true,                    "randomNumber": 488                },                "timestamp": "2021-12-13T02:43:44.155Z"            },            {                "id": "4321",                "someNestedObject": {                    "someBool": false,                    "randomNumber": 484                },                "timestamp": "2018-11-13T02:43:44.155Z"            }        ]    }我想获取数组中对象的计数并将它们拆分为单独的 json 输出以传递给下一个服务。我通过解组原始 json 请求正文然后循环遍历重新编组每个元素并将其附加到正在发送的任何传出消息来执行此操作。就像是,requestBodyBytes := []bytes(JSON_INPUT_STRING)type body struct {    Foo []json.RawMessage `json:"foo"`}var inputs body_ = json.Unmarshal(requestBodyBytes, &inputs)for input := range inputs {    re, _ := json.Marshal(m)    ... do something with re}我看到的是前后的字节数组是不同的,即使字符串表示是相同的。我想知道是否有一种方法可以做到这一点而不改变编码或这里发生的任何事情来改变字节以防止任何不需要的突变?数组中的实际 json 对象都将具有不同的形状,因此我无法使用带有字段验证的结构化 json 定义来提供帮助。此外,上面的代码只是发生了什么的一个例子,所以如果有拼写或语法错误,请忽略它们,因为实际代码如所描述的那样工作。
查看完整描述

1 回答

?
犯罪嫌疑人X

TA贡献2080条经验 获得超4个赞

如果使用json.RawMessage,JSON 源文本将不会被解析,而是按原样存储在其中(它是 a []byte)。

因此,如果您想分发相同的 JSON 数组元素,则无需对其进行任何操作,您可以按原样“移交”它。您不必将其传递给json.Marshal(),它已经是 JSON 编组文本。

所以只需这样做:

for _, input := range inputs.Foo {
    // input is of type json.RawMessage, and it's already JSON text
    }

如果您将 a 传递json.RawMessagejson.Marshal(),它可能会被重新编码,例如压缩(这可能会导致不同的字节序列,但它会保存与 JSON 相同的数据)。

压缩甚至可能是一个好主意,因为从原始上下文(对象和数组)中取出原始缩进可能看起来很奇怪,而且它会更短。要简单地压缩 JSON 文本,您可以json.Compact()这样使用:

for _, input := range inputs.Foo {

    buf := &bytes.Buffer{}

    if err := json.Compact(buf, input); err != nil {

        panic(err)

    }

    fmt.Println(buf) // The compacted array element value

}

如果您不想压缩它,而是自己缩进数组元素,请json.Indent()像这样使用:


for _, input := range inputs.Foo {

    buf := &bytes.Buffer{}

    if err := json.Indent(buf, input, "", "  "); err != nil {

        panic(err)

    }

    fmt.Println(buf)

}

使用您的示例输入,这是第一个数组元素的样子(原始、压缩和缩进):


Orignal:

{

            "id": "1234",

            "someNestedObject": {

                "someBool": true,

                "randomNumber": 488

            },

            "timestamp": "2021-12-13T02:43:44.155Z"

        }


Compacted:

{"id":"1234","someNestedObject":{"someBool":true,"randomNumber":488},"timestamp":"2021-12-13T02:43:44.155Z"}


Indented:

{

  "id": "1234",

  "someNestedObject": {

    "someBool": true,

    "randomNumber": 488

  },

  "timestamp": "2021-12-13T02:43:44.155Z"

}

试试Go Playground上的示例。

另请注意,如果您决定压缩或缩进循环中的单个数组元素,您可以bytes.Buffer在循环之前创建一个简单的,并在每次迭代中重用它,调用它的Buffer.Reset()方法来清除前一个数组的数据。

它可能看起来像这样:

buf := &bytes.Buffer{}

for _, input := range inputs.Foo {

    buf.Reset()

    if err := json.Compact(buf, input); err != nil {

        panic(err)

    }

    fmt.Println("Compacted:\n", buf)

}


查看完整回答
反对 回复 2022-10-24
  • 1 回答
  • 0 关注
  • 148 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号