E
E
exitialis2019-06-27 12:26:36
go
exitialis, 2019-06-27 12:26:36

How to convert struct to map[string]string in Go?

Hello, I'm new to golang and just recently started learning it. There was such a task - it is necessary to go through all the properties in the structure and convert them to map[string][string]. At the same time, the structure has a nested structure, and you need to make sure that the fields from the nested structure from the Key property become keys in the map, and from the Text property become values. I originally used json.Marshal and json.Unmarshal, but the nested structure was lost. I tried to use the github.com/fatih/structs library, but with its help I got stuck at one point - Go swears that there are no Text or Key properties in the interface{} type, what to do? Code example:

type Invoicing struct {
  XMLName    xml.Name 
  Text       string   
  Sign       string   
}

type InvoiceRequest struct {
  Invoicing
}

type ExtFields struct {
  XMLName    xml.Name 
  Fields   []ExtField 
}

type ExtField struct {
  Text string 
  Key  string 
}

type CreateInvoiceRequest struct {
  InvoiceRequest
  Payload struct {
    MerchantId string 
    ShopId     string
    ShopName   string
    OrderId    string 
    Amount     string
    EndDate    string
    ShortDesc  string
    FullDesc   string
    ReturnURL  string
    ExtFields  ExtFields
  }
}

req := CreateInvoiceRequest{}
  req.Payload.Amount = "1"
  req.Payload.EndDate = "2019-06-26 10:00:00"
  email := ExtField{
    Text: "[email protected]",
    Key: "email",
  }
  req.Payload.ExtFields.Fields = make([]ExtField, 0)
  req.Payload.ExtFields.Fields = append(req.Payload.ExtFields.Fields, email)
  
  res := make(map[string]string)
  fields := structs.Fields(req.Payload)
  for _, field := range fields {
    value := field.Value()
    if field.Name() == "fields" {
      if t, ok := value.(string); ok {
        res[field.Value().Key] = field.Value().Text 
      }
    }

    t, ok := value.(string);
    if ok {
      res[field.Name()] = t
    }
  }

Answer the question

In order to leave comments, you need to log in

2 answer(s)
E
exitialis, 2019-06-27
@exitialis

Solved the problem using Type assertions

req := CreateInvoiceRequest{}
  req.Payload.Amount = "1"
  req.Payload.EndDate = "2019-06-26 10:00:00"
  email := ExtField{
    Text: "[email protected]",
    Key: "email",
  }
  req.Payload.ExtFields.Fields = make([]ExtField, 0)
  req.Payload.ExtFields.Fields = append(req.Payload.ExtFields.Fields, email)
  
  res := make(map[string]string)
  fields := structs.Fields(req.Payload)
  for _, field := range fields {
    value := field.Value()
    if field.Name() == "ExtFields" {
      if t, ok := field.Value().(ExtFields); ok && !field.IsZero() {
        for _, extField := range t.Fields {
          res[extField.Key] = extField.Text 
        }
                                continue
      }
      if t, ok := value.(*ExtField); ok {
        res[t.Key] = t.Text 
        continue
      }
    }

    t, ok := value.(string);
    if ok {
      res[field.Name()] = t
      continue
    }
  }

A
Alexander Pavlyuk, 2019-06-27
@pav5000

If you need this, most likely you are doing something wrong. If you really need it, there is a reflect package in the standard library
for such purposes . Your code won't compile because you have to cast interface{} to the correct type. For example like this:

for _, field := range fields {
  if field.Name() == "fields" {
    if field, ok := field.Value().(ExtField); ok {
      res[field.Key] = field.Text
    }
  }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question