Loop over nested JSON elements in Go

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

Loop over nested JSON elements in Go

问题

您遇到的问题是在访问orderaddress.Region时出现错误,错误信息显示OrderAddresses类型没有Region字段或方法。

问题出在OrderAddresses的定义上。OrderAddresses应该是一个结构体切片,而不是一个结构体数组。请将OrderAddresses的定义更改为以下形式:

type OrderAddresses []struct {
    Region      string  `json:"region"`
    Postcode    string  `json:"postcode"`
    Lastname    string  `json:"lastname"`
    Street      string  `json:"street"`
    City        string  `json:"city"`
    Email       string  `json:"email"`
    Telephone   string  `json:"telephone"`
    CountryID   string  `json:"country_id"`
    Firstname   string  `json:"firstname"`
    AddressType string  `json:"address_type"`
    Prefix      *string `json:"prefix"`
    Middlename  *string `json:"middlename"`
    Suffix      *string `json:"suffix"`
    Company     *string `json:"company"`
}

然后,您可以通过索引访问OrderAddresses切片中的每个元素的字段。例如:

for _, orderaddress := range order.Addresses {
    fmt.Println(orderaddress.Region)
}

这样应该就能够正确访问Region字段了。

英文:

I am receiving a JSON response from an API that contains one or more "entities". The JSON looks like this:

{
    "3211": {
        "entity_id": "3211",
        "status": "complete",
        "coupon_code": "COUPON",
        "shipping_description": "Shipping - AU Courier",
        "customer_id": "2775",
        "base_discount_amount": "-50.0000",
        "base_grand_total": "149.0000",
        "base_shipping_amount": "0.0000",
        "base_shipping_tax_amount": "0.0000",
        "base_subtotal": "199.0000",
        "base_tax_amount": "0.0000",
        "base_total_paid": "149.0000",
        "base_total_refunded": null,
        "discount_amount": "-50.0000",
        "grand_total": "149.0000",
        "shipping_amount": "0.0000",
        "shipping_tax_amount": "0.0000",
        "store_to_order_rate": "1.0000",
        "subtotal": "199.0000",
        "tax_amount": "0.0000",
        "total_paid": "149.0000",
        "total_refunded": null,
        "base_shipping_discount_amount": "0.0000",
        "base_subtotal_incl_tax": "199.0000",
        "base_total_due": "0.0000",
        "shipping_discount_amount": "0.0000",
        "subtotal_incl_tax": "199.0000",
        "total_due": "0.0000",
        "increment_id": "200000423",
        "base_currency_code": "AUD",
        "discount_description": "COUPON",
        "remote_ip": "123.123.123.123",
        "store_currency_code": "AUD",
        "store_name": "Australia",
        "created_at": "2017-07-17 03:07:40",
        "shipping_incl_tax": "0.0000",
        "payment_method": "ewayrapid_ewayone",
        "gift_message_from": null,
        "gift_message_to": null,
        "gift_message_body": null,
        "tax_name": null,
        "tax_rate": null,
        "addresses": [
            {
                "region": "South Australia",
                "postcode": "5000",
                "lastname": "Doe",
                "street": "Level 6\n25 Example Street",
                "city": "Adelaide",
                "email": "example@email.com",
                "telephone": "+61 123 456 789",
                "country_id": "AU",
                "firstname": "John",
                "address_type": "billing",
                "prefix": null,
                "middlename": null,
                "suffix": null,
                "company": null
            },
            {
                "region": "South Australia",
                "postcode": "5000",
                "lastname": "Doe",
                "street": "Level 6\n25 Example Street",
                "city": "Adelaide",
                "email": "example@email.com",
                "telephone": "+61 123 456 789",
                "country_id": "AU",
                "firstname": "John",
                "address_type": "shipping",
                "prefix": null,
                "middlename": null,
                "suffix": null,
                "company": null
            }
        ]
	}
}

I have written the following struct types:

type Orders map[string]Order
type Order struct {
	EntityID                   string                    `json:"entity_id"`
	Status                     string                    `json:"status"`
	CouponCode                 string                    `json:"coupon_code"`
	ShippingDescription        string                    `json:"shipping_description"`
	CustomerID                 string                    `json:"customer_id"`
	BaseDiscountAmount         string                    `json:"base_discount_amount"`
	BaseGrandTotal             string                    `json:"base_grand_total"`
	BaseShippingAmount         string                    `json:"base_shipping_amount"`
	BaseShippingTaxAmount      string                    `json:"base_shipping_tax_amount"`
	BaseSubtotal               string                    `json:"base_subtotal"`
	BaseTaxAmount              string                    `json:"base_tax_amount"`
	BaseTotalPaid              string                    `json:"base_total_paid"`
	BaseTotalRefunded          string                    `json:"base_total_refunded"`
	DiscountAmount             string                    `json:"discount_amount"`
	GrandTotal                 string                    `json:"grand_total"`
	ShippingAmount             string                    `json:"shipping_amount"`
	ShippingTaxAmount          string                    `json:"shipping_tax_amount"`
	StoreToOrderRate           string                    `json:"store_to_order_rate"`
	Subtotal                   string                    `json:"subtotal"`
	TaxAmount                  string                    `json:"tax_amount"`
	TotalPaid                  string                    `json:"total_paid"`
	TotalRefunded              string                    `json:"total_refunded"`
	BaseShippingDiscountAmount string                    `json:"base_shipping_discount_amount"`
	BaseSubtotalInclTax        string                    `json:"base_subtotal_incl_tax"`
	BaseTotalDue               string                    `json:"base_total_due"`
	ShippingDiscountAmount     string                    `json:"shipping_discount_amount"`
	SubtotalInclTax            string                    `json:"subtotal_incl_tax"`
	TotalDue                   string                    `json:"total_due"`
	IncrementID                string                    `json:"increment_id"`
	BaseCurrencyCode           string                    `json:"base_currency_code"`
	DiscountDescription        string                    `json:"discount_description"`
	RemoteIP                   string                    `json:"remote_ip"`
	StoreCurrencyCode          string                    `json:"store_currency_code"`
	StoreName                  string                    `json:"store_name"`
	CreatedAt                  string                    `json:"created_at"`
	ShippingInclTax            string                    `json:"shipping_incl_tax"`
	PaymentMethod              string                    `json:"payment_method"`
	TaxName                    string                    `json:"tax_name"`
	TaxRate                    string                    `json:"tax_rate"`
	Addresses                  map[string]OrderAddresses `json:"addresses"`
}

type OrderAddresses []struct {
	Region      string  `json:"region"`
	Postcode    string  `json:"postcode"`
	Lastname    string  `json:"lastname"`
	Street      string  `json:"street"`
	City        string  `json:"city"`
	Email       string  `json:"email"`
	Telephone   string  `json:"telephone"`
	CountryID   string  `json:"country_id"`
	Firstname   string  `json:"firstname"`
	AddressType string  `json:"address_type"`
	Prefix      *string `json:"prefix"`
	Middlename  *string `json:"middlename"`
	Suffix      *string `json:"suffix"`
	Company     *string `json:"company"`
}

I am then trying to process it like so (the getFromOrdersAPI(page) function returns the JSON mentioned above in the Orders type):

for page := 1; page < 3; page++ {
	orders := getFromOrdersAPI(page)
	for _, order := range orders {
		//Process all the order items except addresses
		fmt.Println("Processing entity:", orders.EntityID)
		
		for _, orderaddress := range order.Addresses {
			//Trying to access address values - example below
			fmt.Println(orderaddress.Region)
		}
	}
}

When running this, I get the error:

> orderaddress.Region undefined (type OrderAddresses has no field or method Region)

Where am I going wrong?

答案1

得分: 2

你遇到的错误是由于你定义OrderAddresses结构体的方式不正确。你应该使用以下方式进行定义:

type OrderAddresses struct {
    // fields of OrderAddresses
}

不要使用大括号,这样你的编译错误应该会消失。

话虽如此,根据我查看的数据块,我不确定你的 JSON 是否会按照你的预期进行解析。看起来 JSON 数据中的 addresses 是一个数组。这意味着你应该将其表示为一个 OrderAddresses 的切片,而不是一个 map

Addresses []OrderAddresses `json:"addresses"`

希望对你有所帮助!

英文:

The error you are getting is due to the way you are defining your OrderAddresses struct. Instead of

type OrderAddresses []struct {

If you use

type OrderAddresses struct {

without the braces, your compile error should go away.

That being said, I'm not sure if your json will parse as you expect given the blob I'm looking at. It appears that addresses in the json blob is an array. This means that instead of representing it as

Addresses map[string]OrderAddresses `json:"addresses"`

You should simply make it a slice of OrderAddresses

Addresses []OrderAddresses `json:"addresses"`

答案2

得分: 1

你之所以会收到orderaddress.Region undefined错误是因为根据你的OrderAddresses类型,在你的for循环中,orderaddress是一个数组。显然,数组没有名为Region的字段或方法。

如果你想查看for循环中的orderaddress的内容,你可以像这样使用range

for _, orderaddress := range order.Addresses {
  for _, addressData := range orderaddress{
      fmt.Printf("%+v\n", addressData)
  }
}

我在这里创建了一个示例:链接

话虽如此,在你的JSON数据中,addresses字段是一个数组,而不是一个映射。所以你的Order结构体中的Addresses字段也必须是一个数组。然后你的OrderAddresses应该只是一个结构体,而不是结构体的切片。

英文:

The reason you are getting the orderaddress.Region undefined error is because the orderaddress in your for loop is an array, based on your OrderAddresses type. Obviously, an array doesn't have fields or methods named Region.

If you want to examine what orderaddress in your for loop looks like, you can range over it like this:

for _, orderaddress := range order.Addresses {
  for _, addressData := range orderaddress{
      fmt.Printf("%+v\n", addressData)
  }
}

I have created an example here.

That said, in your JSON data, the addresses field is an array, not a map. So the Addresses field in your Order struct must be an array too. Then your OrderAddresses should just be a struct, not a slice of struct.

huangapple
  • 本文由 发表于 2017年8月15日 11:58:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/45686269.html
匿名

发表评论

匿名网友

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

确定