从非解组数据准备一个 JSON 对象。

huangapple go评论74阅读模式
英文:

Prepare a json object from unmarshaled data

问题

我有这样的JSON数据:

json: {"opt1":200,"opt3":"1","opt4":"13","opt5":null,"products":[{"product_id":1,"price":100,"variant_id":100},{"product_id":1,"price":100,"variant_id":null}]}

我使用以下结构化数据:

type Products struct {
    Product_id int
    Price json.Number
    Variant_id int
}


type Pdata struct {
    Products []Products `json:"products"`
}

然后我使用unmarshal进行解析:

jsonb := []byte(jsonVal)
var data Pdata
err := json.Unmarshal(jsonb, &data)
if err != nil {
    fmt.Println(err)
    return
}

得到的输出如下:

{[{1 100 100} {2 100 0}]}

现在我需要将该数据转换为以下JSON对象:

{"purchased_products": [{"product_id": 1,"price": 1200,"variation_id": 100},{"product_id": 2,"price": 100,"variation_id": null}]}

然后,我需要将其赋值给"json":

var d = map[string]string{
    "json":        jsonVal,
    "created_at":  time.Now().Format("2006-01-02 15:04:05"),
    "updated_at":  time.Now().Format("2006-01-02 15:04:05"),
}

我该如何做到这一点?

英文:

I have json data like this:

json: {"opt1":200,"opt3":"1","opt4":"13","opt5":null,"products":[{"product_id":1,"price":100,"variant_id":100},{"product_id":1,"price":100,"variant_id":null}]}

I have structured it using

type Products struct {
    Product_id int
    Price json.Number
    Variant_id int
}


type Pdata struct {
	Products []Products `json:"products"`
}

Then I use unmarshal

jsonb := []byte(jsonVal)
	var data Pdata
	err := json.Unmarshal(jsonb, &data)
	if err != nil {
		fmt.Println(err)
		return
	}

And get output like

{[{1 100 100} {2 100 0}]}

Now I need to convert that data into a json object like this

{"purchased_products": [{"product_id": 1,"price": 1200,"variation_id": 100},{"product_id": 2,"price": 100,"variation_id": null}]}

After that, I need to assign it to "json"

var d = map[string]string{
	"json":        jsonVal,
	"created_at":  time.Now().Format("2006-01-02 15:04:05"),
	"updated_at":  time.Now().Format("2006-01-02 15:04:05"),
}

How can I do it?

答案1

得分: 2

创建一个名为PurchasedProducts的类型,如下所示。

type PurchasedProducts struct {
	Products []Products `json:"purchased_products"`
}

然后,初始化一个PurchasedProducts类型的变量,并将解码后的产品赋值给PurchasedProducts,如下所示。

pProducts := PurchasedProducts{Products: data.Products}
jsonByte, err := json.Marshal(pProducts)
if err != nil {
	fmt.Println(err)
	return
}

将该[]byte数组转换为字符串,并将其赋值给map,如下所示。

var d = map[string]string{
	"json":        string(jsonByte),
	"created_at":  time.Now().Format("2006-01-02 15:04:05"),
	"updated_at":  time.Now().Format("2006-01-02 15:04:05"),
}

你可以在这里运行并查看完整的代码。

英文:

Create a type (eg : PurchasedProducts) as below.

type PurchasedProducts struct {
	Products []Products `json:"purchased_products"`
}

And init a PurchasedProducts type variable and assign your unmarshaled products to Purchased products as below.

    pProducts := PurchasedProducts{Products: data.Products}
	jsonByte, err := json.Marshal(pProducts)
	if err != nil {
		fmt.Println(err)
		return
	}

And convert that []byte array to a string and assign it to the map like below.

    var d = map[string]string{
		"json":        string(jsonByte),
		"created_at":  time.Now().Format("2006-01-02 15:04:05"),
		"updated_at":  time.Now().Format("2006-01-02 15:04:05"),
	}

You can run and see full code here.

答案2

得分: 1

对于可为空的字段,您可以使用指针。例如,如果variant_id JSON字段可以是整数或JSON的null,并且您想保留该信息,那么您可以将Variant_id int更改为Variant_id *int

type Product struct {
	Product_id int         `json:"product_id"`
	Price      json.Number `json:"price"`
	Variant_id *int        `json:"variant_id"`
}

要在解组和编组之间更改JSON字段名称,您可以声明第二个具有与原始结构相同字段的Products结构,但使用结构标签定义所需的字段名称。然后,如果结构在其他方面是等效的,您可以在它们之间进行转换。

type Product struct {
	Product_id int         `json:"product_id"`
	Price      json.Number `json:"price"`
	Variant_id int         `json:"variant_id"`
}

type PurchasedProduct struct {
	Product_id int         `json:"product_id"`
	Price      json.Number `json:"price"`
	Variant_id int         `json:"variation_id"` // 这里的 variant_id 变成了 variation_id
}

然后,如果p的类型是Product,您可以简单地将其转换为PurchasedProduct,如下所示:

pp := PurchasedProduct(p)

要将转换卸载到编组过程中,您可以使原始类型实现json.Marshaler接口,并在其中进行转换。

func (p Product) MarshalJSON() ([]byte, error) {
	type P struct {
		Product_id int         `json:"product_id"`
		Price      json.Number `json:"price"`
		Variant_id *int        `json:"variation_id"`
	}
	return json.Marshal(P(p))
}

有了上述内容,您可以执行以下操作:

func main() {
	// 解组
	var pd Pdata
	err := json.Unmarshal(data, &pd)
	if err != nil {
		panic(err)
	}

	// 编组
	out, err := json.MarshalIndent(pd, "", "  ")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(out))
}

链接:https://play.golang.org/p/0gnrjgUslza

英文:

For nullable fields you can use pointers, so for example if the variant_id json field can be an integer or a json null, and you want to retain that information, then you can change Variant_id int to Variant_id *int.

type Product struct {
	Product_id int         `json:"product_id"`
	Price      json.Number `json:"price"`
	Variant_id *int        `json:"variant_id"`
}

To change json field names between unmarshal and marshal you can declare a second Products struct with the same fields as the original but with struct tags defining the desired field names, then, if the structs are, in all other respects, equivalent you can convert between them.

type Product struct {
	Product_id int         `json:"product_id"`
	Price      json.Number `json:"price"`
	Variant_id int         `json:"variant_id"`
}

type PurchasedProduct struct {
	Product_id int         `json:"product_id"`
	Price      json.Number `json:"price"`
	Variant_id int         `json:"variation_id"` // here variant_id becomes variation_id
}

Then, if p is of type Product, you can simply convert it to PurchasedProduct like so:

pp := PurchasedProduct(p)

To offload the conversion to the marshaling process you can have the original types implement the json.Marshaler interface and do the conversion there.

func (p Product) MarshalJSON() ([]byte, error) {
	type P struct {
		Product_id int         `json:"product_id"`
		Price      json.Number `json:"price"`
		Variant_id *int        `json:"variation_id"`
	}
	return json.Marshal(P(p))
}

With the above you can do the following:

func main() {
	// unmarshal
	var pd Pdata
	err := json.Unmarshal(data, &pd)
	if err != nil {
		panic(err)
	}

	// marshal
	out, err := json.MarshalIndent(pd, "", "  ")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(out))
}

https://play.golang.org/p/0gnrjgUslza

答案3

得分: 1

只需定义另外两个结构体来模拟第二个JSON对象:

type Pdata2 struct {
    PurchasedProducts []Product2
}

type Product2 struct {
    Product_id    int
    Price         json.Number
    Variation_id  *int // 指向int的指针
}

Variation_id字段是*int类型,因为你所需的输出JSON显示为"variation_id": null。如果将该字段声明为普通的int类型,它的零值将被编组为0

然后使用前面的值初始化这些结构体:

func main() {
    data2 := Pdata2{
        PurchasedProducts: make([]Product2, len(data.Products)),
    }

    for i, p := range data.Products {
        data2.PurchasedProducts[i] = Product2{
            Product_id:   p.Product_id,
            Price:        p.Price,
            Variation_id: nullableInt(p.Variant_id),
        }
    }

    b, err := json.Marshal(data2)
    if err != nil {
        // ... 处理错误
    }
    var d = map[string]string{
        "json": string(b),
        // ...
    }
    fmt.Println(d)
}

func nullableInt(n int) *int {
    if n == 0 {
        return nil
    }
    return &n
}

Playground: https://play.golang.org/p/xhsmHNBjRKN

英文:

Simply define two more structs that model the second JSON object:

type Pdata2 struct {
    PurchasedProducts []Product2
}

type Product2 struct {
    Product_id    int
    Price         json.Number
    Variation_id  *int // pointer to int
}

The Variation_id field is an *int type because your required output JSON shows "variation_id": null. If you declare the field as simple int, its zero value will be marshaled to 0.

Then initialize those structs using values from the previous ones:

func main() {
	data2 := Pdata2{
		PurchasedProducts: make([]Product2, len(data.Products)),
	}

	for i, p := range data.Products {
		data2.PurchasedProducts[i] = Product2{
			Product_id:   p.Product_id,
			Price:        p.Price,
			Variation_id: nullableInt(p.Variant_id),
		}
	}

	b, err := json.Marshal(data2)
	if err != nil {
		// ... handle error
	}
	var d = map[string]string{
		"json": string(b),
		// ...
	}
    fmt.Println(d)
}

func nullableInt(n int) *int {
    if n == 0 {
        return nil
    }
    return &n
}

Playground: https://play.golang.org/p/xhsmHNBjRKN

答案4

得分: 0

给你翻译好的代码如下:

package main

import (
	"encoding/json"
	"log"
	"os"
	"time"
)

type (
	Product struct {
		ProductID int         `json:"product_id"`
		VariantID int         `json:"variant_id"`
		Price     json.Number `json:"price"`
	}
	Products []Product

	OutputProduct struct {
		ProductID int         `json:"product_id"`
		VariantID int         `json:"variation_id"`
		Price     json.Number `json:"price"`
	}
)

func (p Product) ToOutputProduct() OutputProduct {
	return OutputProduct{
		ProductID: p.ProductID,
		VariantID: p.VariantID,
		Price:     p.Price,
	}
}

func (p Products) ToOutputProducts() []OutputProduct {
	outputProducts := make([]OutputProduct, len(p))
	for i := 0; i < len(p); i++ {
		outputProducts[i] = p[i].ToOutputProduct()
	}
	return outputProducts
}

func main() {
	var inputJSON = `{"opt1":200,"opt3":"1","opt4":"13","opt5":null,"products":[{"product_id":1,"price":100,"variant_id":100},{"product_id":1,"price":100,"variant_id":null}]}`

	var parsedInput struct {
		Products Products
	}
	if err := json.Unmarshal([]byte(inputJSON), &parsedInput); err != nil {
		log.Fatal(err)
	}

	var output = map[string]interface{}{
		"json": map[string][]OutputProduct{
			"purchased_products": parsedInput.Products.ToOutputProducts(),
		},
		"created_at": time.Now().Format("2006-01-02 15:04:05"),
		"updated_at": time.Now().Format("2006-01-02 15:04:05"),
	}
	encoder := json.NewEncoder(os.Stdout)
	encoder.SetIndent(" ", "  ")
	if err := encoder.Encode(output); err != nil {
		log.Fatal(err)
	}
}

希望对你有帮助!

英文:

Here you are.
Assumptions are that:

  • Product is a model which could be much more complicated, thus it has dedicated structs. Thus transformation from Product to OutputProduct can be unit tested separately.
  • It is one time use application, not a part of the application which exposes an API. Otherwise it should be properly separated into layers and the output should be written as a structure.
package main
import (
&quot;encoding/json&quot;
&quot;log&quot;
&quot;os&quot;
&quot;time&quot;
)
type (
Product struct {
ProductID int `json:&quot;product_id&quot;`
VariantID int `json:&quot;variant_id&quot;`
Price     json.Number
}
Products []Product
OutputProduct struct {
ProductID int `json:&quot;product_id&quot;`
VariantID int `json:&quot;variation_id&quot;`
Price     json.Number
}
)
func (p Product) ToOutputProduct() OutputProduct {
return OutputProduct{
ProductID: p.ProductID,
VariantID: p.VariantID,
Price:     p.Price,
}
}
func (p Products) ToOutputProducts() []OutputProduct {
outputProducts := make([]OutputProduct, len(p))
for i := 0; i &lt; len(p); i++ {
outputProducts[i] = p[i].ToOutputProduct()
}
return outputProducts
}
func main() {
var inputJSON = `{&quot;opt1&quot;:200,&quot;opt3&quot;:&quot;1&quot;,&quot;opt4&quot;:&quot;13&quot;,&quot;opt5&quot;:null,&quot;products&quot;:[{&quot;product_id&quot;:1,&quot;price&quot;:100,&quot;variant_id&quot;:100},{&quot;product_id&quot;:1,&quot;price&quot;:100,&quot;variant_id&quot;:null}]}`
var parsedInput struct {
Products Products
}
if err := json.Unmarshal([]byte(inputJSON), &amp;parsedInput); err != nil {
log.Fatal(err)
}
var output = map[string]interface{}{
&quot;json&quot;:       map[string][]OutputProduct{
&quot;purchased_products&quot;: parsedInput.Products.ToOutputProducts(),
},
&quot;created_at&quot;: time.Now().Format(&quot;2006-01-02 15:04:05&quot;),
&quot;updated_at&quot;: time.Now().Format(&quot;2006-01-02 15:04:05&quot;),
}
encoder := json.NewEncoder(os.Stdout)
encoder.SetIndent(&quot; &quot;, &quot;  &quot;)
if err := encoder.Encode(output); err != nil {
log.Fatal(err)
}
}

答案5

得分: 0

根据评论中的建议:

package main

import (
	"encoding/json"
	"log"
	"time"
)

type Products struct {
	Product_id int `json:"product_id"`
	Price      int `json:"price"`
	Variant_id int `json:"variant_id"`
}

type ProductData struct {
	Products []Products `json:"products"`
}

type Response struct {
	Json      json.RawMessage `json:"json"`
	CreatedAt string          `json:"created_at"`
	UpdatedAt string          `json:"updated_at"`
}

func main() {
	productJson := `{
		"opt1": 200,
		"opt3": "1",
		"opt4": "13",
		"opt5": null,
		"products": [
			{ "product_id": 1, "price": 100, "variant_id": 100 },
			{ "product_id": 1, "price": 100, "variant_id": null }
		]
	}`

	productData := &ProductData{}
	err := json.Unmarshal([]byte(productJson), &productData)
	if err != nil {
		panic(err)
	}

	b, err := json.Marshal(map[string]interface{}{"purchased_products": productData.Products})
	if err != nil {
		panic(err)
	}

	d := &Response{
		Json:      b,
		CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
		UpdatedAt: time.Now().Format("2006-01-02 15:04:05"),
	}

	out, err := json.Marshal(d)
	if err != nil {
		panic(err)
	}

	log.Println(string(out))
}

输出结果:

2009/11/10 23:00:00 {"json":{"purchased_products":[{"product_id":1,"price":100,"variant_id":100},{"product_id":1,"price":100,"variant_id":0}]},"created_at":"2009-11-10 23:00:00","updated_at":"2009-11-10 23:00:00"}
英文:

Based on the suggestions from comments:

package main
import (
&quot;encoding/json&quot;
&quot;log&quot;
&quot;time&quot;
)
type Products struct {
Product_id int `json:&quot;product_id&quot;`
Price      int `json:&quot;price&quot;`
Variant_id int `json:&quot;variant_id&quot;`
}
type ProductData struct {
Products []Products `json:&quot;products&quot;`
}
type Response struct {
Json      json.RawMessage `json:&quot;json&quot;`
CreatedAt string          `json:&quot;created_at&quot;`
UpdatedAt string          `json:&quot;updated_at&quot;`
}
func main() {
productJson := `{
&quot;opt1&quot;: 200,
&quot;opt3&quot;: &quot;1&quot;,
&quot;opt4&quot;: &quot;13&quot;,
&quot;opt5&quot;: null,
&quot;products&quot;: [
{ &quot;product_id&quot;: 1, &quot;price&quot;: 100, &quot;variant_id&quot;: 100 },
{ &quot;product_id&quot;: 1, &quot;price&quot;: 100, &quot;variant_id&quot;: null }
]
}`
productData := &amp;ProductData{}
err := json.Unmarshal([]byte(productJson), &amp;productData)
if err != nil {
panic(err)
}
b, err := json.Marshal(map[string]interface{}{&quot;purchased_products&quot;: productData.Products})
if err != nil {
panic(err)
}
d := &amp;Response{
Json:      b,
CreatedAt: time.Now().Format(&quot;2006-01-02 15:04:05&quot;),
UpdatedAt: time.Now().Format(&quot;2006-01-02 15:04:05&quot;),
}
out, err := json.Marshal(d)
if err != nil {
panic(err)
}
log.Println(string(out))
}

Output:

2009/11/10 23:00:00 {&quot;json&quot;:{&quot;purchased_products&quot;:[{&quot;product_id&quot;:1,&quot;price&quot;:100,&quot;variant_id&quot;:100},{&quot;product_id&quot;:1,&quot;price&quot;:100,&quot;variant_id&quot;:0}]},&quot;created_at&quot;:&quot;2009-11-10 23:00:00&quot;,&quot;updated_at&quot;:&quot;2009-11-10 23:00:00&quot;}

huangapple
  • 本文由 发表于 2021年7月2日 13:50:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/68220191.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定