Подготовьте объект json из немаршалированных данных
У меня есть такие данные 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"),
}
Как мне это сделать?
5 ответов
Создайте тип (например, PurchasedProducts), как показано ниже.
type PurchasedProducts struct {
Products []Products `json:"purchased_products"`
}
И инициализируйте переменную типа PurchasedProducts и назначьте ваши немаршалированные продукты приобретенным продуктам, как показано ниже.
pProducts := PurchasedProducts{Products: data.Products}
jsonByte, err := json.Marshal(pProducts)
if err != nil {
fmt.Println(err)
return
}
И преобразовать это
[]byte
array в строку и назначьте его карте, как показано ниже.
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"),
}
Вы можете запустить и увидеть полный код здесь .
Для полей, допускающих значение NULL, вы можете использовать указатели, например, если
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 между unmarshal и marshal, вы можете объявить второй
Products
struct с теми же полями, что и исходный, но со структурными тегами, определяющими желаемые имена полей, тогда, если структуры во всех других отношениях эквивалентны, вы можете конвертировать между ними.
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
}
Тогда, если
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() {
// 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))
}
Просто определите еще две структуры, моделирующие второй объект JSON:
type Pdata2 struct {
PurchasedProducts []Product2
}
type Product2 struct {
Product_id int
Price json.Number
Variation_id *int // pointer to 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 {
// ... 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
}
Игровая площадка: https://play.golang.org/p/xhsmHNBjRKN
Вот, пожалуйста. Предположения таковы:
- Продукт - это модель, которая может быть намного сложнее, поэтому у нее есть специальные структуры. Таким образом, преобразование из Product в OutputProduct можно тестировать отдельно.
- Это одноразовое приложение, а не часть приложения, предоставляющего API. В противном случае он должен быть правильно разделен на слои, а результат должен быть записан в виде структуры.
package main
import (
"encoding/json"
"log"
"os"
"time"
)
type (
Product struct {
ProductID int `json:"product_id"`
VariantID int `json:"variant_id"`
Price json.Number
}
Products []Product
OutputProduct struct {
ProductID int `json:"product_id"`
VariantID int `json:"variation_id"`
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 < 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)
}
}
На основе предложений из комментариев:
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"}