带有依赖条件的动态数据结构(嵌套json)

时间:2019-01-02 16:40:36

标签: go

我正在尝试创建动态嵌套的json。我知道go是静态类型,并且有多种方法可以创建动态对象(接口),并且想知道是否有一种方法可以解决嵌套json中的依赖项映射

样本json

 [
{
  "display" : "Environment" ,
  "field" : "test_env" ,
  "value" : {
  "display" : "staging",
  "value" : "s"
},
   "type" : "drop-down" ,
   "data" : [
    {
      "display" : "version" ,
      "field" : "test_version" ,
      "value" : {
       "display" : "1.1.9" ,
        "value" : "1.1.9"
      },
      "type" : "drop-down" ,
      "data" : [
        {
          "display" : "DataCenter" ,
          "field" : "test_dc" ,
          "value" : {
           "display" : "washington",
           "value" : "wa"
         },
          "type" : "drop-down" ,
         "data" : [{
         "display" : "Secondary" ,
         "field" : "test_secondary_dc" ,
         "value" : {
             "display" : "miami" ,
             "value" : "mi"
           },
            "type" : "drop-down" ,
            "data" : [{
              "display" : "Size" ,
              "field" : "test_size" ,
              "value" : {
                "display" : "small" ,
                "value" : "s"
                  }
              }]
            }]
        }
      ]
     }
   ]
 },
 {
  "display" : "Environment" ,
  "field" : "test_env" ,
  "value" : {
    "display" : "production",
    "value" : "p"
  },
  "type" : "drop-down" ,
  "data" : [
    {
      "display" : "version" ,
      "field" : "test_version" ,
      "value" : {
        "display" : "1.1.9" ,
        "value" : "1.1.9"
       },
      "type" : "drop-down" ,
      "data" : [
         {
          "display" : "DataCenter" ,
          "field" : "test_dc" ,
          "value" : {
            "display" : "miami",
            "value" : "mi"
          },
          "type" : "drop-down" ,
          "data" : [{
            "display" : "Secondary" ,
            "field" : "test_secondary_dc" ,
            "value" : {
              "display" : "washington" ,
              "value" : "wa"
            },
            "type" : "drop-down" ,
            "data" : [{
              "display" : "Size" ,
              "field" : "test_size" ,
              "value" : {
                "display" : "medium" ,
                "value" : "m"
             }
              }]
            }]
        }
      ]
    }
  ]
}
]

示例代码:

package main

import (
    "fmt"
     "reflect"
 )


    // struct definition ///

   type  RootElem struct {
        RDisplay string `json:"display"`
        RField string `json:"field"`
        RType string `json:"type"`
        RData RSlice `json:"data"`
        RValue RValue `json:"value"`
        }

type RValue struct {
    Display string `json:"display"`
    Evalue string `json:"value"`
    }

type Vars struct {
    Env      string `json:"environment"`
    Version  string `json:"version"`
    Zone     string `json:"zone"`
    PDcenter string `json:"primary_dc"`
    SDcenter string `json:"secondary_dc,omitempty"`
    Size     string `json:"size"`
  }

type RSlice []RootElem

func valueFactory(etype, evalue string) string {
  switch (etype) {
    case "ENVIRONMENT":
      return environmentValue(evalue);
    case "VERSION":
      return versionValue(evalue);
    case "ZONE":
      return zoneValue(evalue);
    case "PRIMARYDC":
      return primaryValue(evalue);
    case "SECONDARYDC":
      return secondaryValue(evalue);
    case "SIZE":
      return sizeValue(evalue);
    default:
      return("Specifying a type we don't have.");
   }
  }

func sizeValue(sz string) string {
   switch (sz) {
     case "Small":
      return "s"
     case "Medium":
      return "m"
     case "Large" :
       return "l"
     default:
       return "This is not a size environment value"
    }
}


func environmentValue(env string) string {
  switch (env) {
    case "Production":
      return "p"
    case "staging":
      return "s"
    default:
      return "This is not a valid environment value"
  }
}

func versionValue(ver string) string {
  switch (ver) {
     case "1.1.9":
       return "1.1.9"
     default:
      return "This is not a valid version value"
  }
 }

 func zoneValue(zone string) string {
  switch (zone) {
    case "BLACK":
     return "Black"
    case "GREEN" :
      return "Green"
   default:
     return "This is not a valid zone value"
  }
}

  func primaryValue(pdc string) string {
  switch (pdc) {
     case "washington ":
       return "wa"
    case "Miami" :
       return "mi"

     default:
       return "This is not a valid primary data center value"
  }
 }

 func secondaryValue(sdc string) string {
  switch (sdc) {
   case "washington":
     return "wa"
    case "Miami" :
      return "mi"
    default:
      return "This is not a valid secondary data center value"
 }
}


func dataGeneric(display, field, etype string) (relm RootElem) {
 relm.RDisplay =  display
     relm.RField = field
     relm.RValue.Display =  ""
 relm.RValue.Evalue =  ""
     relm.RType = etype
     return  relm
 }

 func dataEnvironment() RootElem {
   display := "Environment"
   field := "test_env"
   etype := "dropdown"
   return dataGeneric(display, field, etype)
}

func dataVersion() RootElem {
  display := "Version"
  field := "test_version"
  etype := "dropdown"
  return dataGeneric(display, field, etype)
 }

func dataZone() RootElem {
  display := "Zone"
  field := "test_zone"
  etype := "dropdown"
  return dataGeneric(display, field, etype)
}

func dataPrimary() RootElem {
 display := "Primary Data Center"
 field := "test_dc"
 etype := "dropdown"
 return dataGeneric(display, field, etype)
}

func dataSecondary() RootElem {
  display := "Secondary Data Center"
  field := "test_secondary_dc"
  etype := "dropdown"
  return dataGeneric(display, field, etype)
}

func dataSize() RootElem {
  display := "size"
  field := "test_size"
  etype := "dropdown"
   return dataGeneric(display, field, etype)
}


func dataFactory(etype string) RootElem {

 var rem RootElem
  switch (etype) {
     case "ENVIRONMENT":
      return dataEnvironment()
    case "VERSION":
      return dataVersion()
    case "ZONE":
      return dataZone()
    case "PRIMARYDC":
      return dataPrimary()
    case "SECONDARYDC":
      return dataSecondary()
    case "SIZE":
      return dataSize()
  }
   return rem
}




func main() {

 // sample element ///
var elment = Vars{
    Env: "Production" ,
    Version: "1.1.9" ,
    Zone: "GREEN" ,
    PDcenter: "Washington" ,
    SDcenter: "Miami" ,
    Size: "Small" ,
    }


var Dict = []string{"ENVIRONMENT" , "VERSION" , "ZONE" , "PRIMARYDC" , "SECONDARYDC" , "SIZE" }


var newData, finalElem RootElem
for i := 0 ; i < reflect.ValueOf(elment).NumField() ; i++ {
    currentElement := reflect.ValueOf(elment).Field(i).Interface()
    currentElemType := Dict[i]

    newData = dataFactory(currentElemType)
    newData.RValue.Display = currentElement.(string)
    newData.RValue.Evalue = valueFactory(currentElemType, currentElement.(string))

    if finalElem.RDisplay == "" {
        finalElem = newData
    } else {
            if len(finalElem.RData) == 0 {
         finalElem.RData = append(finalElem.RData, newData)
            } else {
                if len(finalElem.RData[0].RData) == 0 {
                 finalElem.RData[0].RData = append( finalElem.RData[0].RData , newData)
                } else {
                    if len(finalElem.RData[0].RData[0].RData) == 0 {
                    finalElem.RData[0].RData[0].RData = append (finalElem.RData[0].RData[0].RData , newData)
                    } else {
                        if len(finalElem.RData[0].RData[0].RData[0].RData) == 0 {
                        finalElem.RData[0].RData[0].RData[0].RData = append(finalElem.RData[0].RData[0].RData[0].RData, newData )
                        } else {
                            finalElem.RData[0].RData[0].RData[0].RData[0].RData = append(finalElem.RData[0].RData[0].RData[0].RData[0].RData, newData)
                            }
                        }
                    }
                }
        }
}

 fmt.Println("final element" , finalElem)

}

想知道是否有一种方法可以编写用于在go中创建动态嵌套json的递归函数吗?

谢谢

1 个答案:

答案 0 :(得分:0)

我不完全知道您要达到的目标,我运行了您的应用程序,并且您正在从平面结构中构建一棵树。为什么以及您最初的计划不清楚。

但是,应用程序不断增长的if树始终与最后附加的RootElem相同,可以编写如下。如您所见,您的if结构现在独立于NumField()

    var appendHere *RootElem

    for i := 0; i < reflect.ValueOf(elment).NumField(); i++ {

        [ ... stuff deleted ... ]

        if finalElem.RDisplay == "" {
            finalElem = newData
            appendHere = &finalElem
        } else {
            appendHere.RData = append(appendHere.RData, newData)
            appendHere = &(appendHere.RData[0])
        }

    }

    fmt.Println("final element", finalElem)
}

将其写为评论,但答案太大,无法发表评论。