From 7e3e2a21857f05321c26c49dba54a81c55da2f7a Mon Sep 17 00:00:00 2001 From: Nathan Coad Date: Tue, 30 May 2023 13:32:24 +1000 Subject: [PATCH] Removed git ignored files --- .gitignore | 6 +- README.md | 5 ++ cmd/.DS_Store | Bin 6148 -> 0 bytes cmd/main/main.go | 205 +++++++++++++++++++++++++++++++-------------- internal/.DS_Store | Bin 6148 -> 0 bytes 5 files changed, 154 insertions(+), 62 deletions(-) delete mode 100644 cmd/.DS_Store delete mode 100644 internal/.DS_Store diff --git a/.gitignore b/.gitignore index fb0f8ba..8ed9d14 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,8 @@ json2excel # Ignore test data -*.json \ No newline at end of file +*.json + +# Ignore Mac DS_Store files +.DS_Store +**/.DS_Store \ No newline at end of file diff --git a/README.md b/README.md index 52af935..f0ad8e2 100644 --- a/README.md +++ b/README.md @@ -14,3 +14,8 @@ It expects that the json input is formatted as an object containing an array of | freezeTopRow | true | Freezes the first row of the Excel worksheet | | autofilter | true | Sets the auto filter on the first row | | autowidth | true | Automatically set the column width to fit contents | + +## Advanced configuration + +Advanced settings can be provided via a top level json key named "config". Below are options that can be set via this config key: +- key-order \ No newline at end of file diff --git a/cmd/.DS_Store b/cmd/.DS_Store deleted file mode 100644 index 3dd2bdadf75a561da4cc9390991dac8d8d7de4be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T^D5T4Nr1uuK_m{-_0h^0Qk-bK3w6{^;%$YM z8A!fK<|oYuO)^Bp&1=6VS`kr=Cdi^Jh)ge<&dm7&$daRf*$!Pw0|uue^6eFkbWcz8 zJpKOt}YQrQ`>e!>R_wC-kZ1E&yVYA!ZG!~+INo!xhKoG>I^so&VV!E z3>I4aa;izi5~hHJsRr54M$miWe@cBY!CF#8J_EXTTYlGjOiMmE8X~_+=K0{CS9v zoB?OxpE1ByyJ;J2%I?;K?a5sm(C*Mg#4n2ifj)Z#U?AtnRWYhPhz`GKm=z_9%$IPW OKLiRP-Z=w*z`!?x@h=hp diff --git a/cmd/main/main.go b/cmd/main/main.go index 576c91b..0869527 100644 --- a/cmd/main/main.go +++ b/cmd/main/main.go @@ -7,6 +7,7 @@ import ( "log" "os" "reflect" + "strings" "time" "unicode/utf8" @@ -16,9 +17,16 @@ import ( // Initial concept from https://stackoverflow.com/q/68621039 +type Config struct { + keyOrder map[int]string +} + +var config Config + func main() { //jsonFile := "test.json" parentNode := "input" + configNode := "config" //worksheetName := "Sheet2" //outputFilename := "test.xlsx" @@ -55,6 +63,91 @@ func main() { // Truncate worksheetName to the maximum 31 characters worksheetName = TruncateString(worksheetName, 31) + // Read the json input file + if fileExists(inputJson) { + s, err = os.ReadFile(inputJson) + if err != nil { + panic(err) + } + } else { + fmt.Printf("Input JSON file '%s' does not exist.\n", inputJson) + os.Exit(1) + } + + // Unmarshal the json into an orderedmap to preserve the ordering of json structure + o := orderedmap.New() + err = json.Unmarshal([]byte(s), &o) + if err != nil { + error := fmt.Sprintf("JSON Unmarshal error %s\n", err) + panic(error) + } + + // Assume that our content is within the first top-level key + topLevel := o.Keys() + + // Check for config embedded in json + if strings.EqualFold(topLevel[0], configNode) && len(topLevel) > 1 { + fmt.Printf("Found configNode as toplevel json key, setting parentNode as '%s'\n", topLevel[1]) + parentNode = topLevel[1] + + config.keyOrder = make(map[int]string) + + // Get a reference to the top level node we specified earlier + configInterface, ok := o.Get(configNode) + if !ok { + fmt.Printf("Missing key for multitype array when reading embedded config") + } + + // Get an interface that we can work with to access the sub elements + //configSlice := configInterface + //fmt.Printf("%v\n", configSlice) + + // Get the keys for the first element so we know what config options have been specified + configMap := configInterface.(orderedmap.OrderedMap) + configKeys := configMap.Keys() + + // Parse each key into our config struct + for _, key := range configKeys { + if strings.EqualFold(key, "key-order") { + fmt.Printf("Found config element for key-order\n") + e, _ := configMap.Get(key) + for i, e := range strings.Split(e.(string), ",") { + config.keyOrder[i] = e + } + fmt.Printf("Column order is now : '%v'\n", config.keyOrder) + } else if strings.EqualFold(key, "overwrite-file") { + fmt.Printf("Found config element for overwriting output file\n") + e, _ := configMap.Get(key) + overwriteFile = e.(bool) + } + } + } else if strings.EqualFold(topLevel[0], configNode) { + error := "Only found config in first level of json keys" + panic(error) + } else { + fmt.Printf("Detected toplevel json key as: '%s'\n", topLevel[0]) + parentNode = topLevel[0] + } + + // Get a reference to the top level node we specified earlier + vislice, ok := o.Get(parentNode) + if !ok { + fmt.Printf("Missing key for multitype array") + } + + // Get an interface that we can work with to access the sub elements + vslice := vislice.([]interface{}) + + // Check that the first element is what we expected + if _, ok := vslice[0].(orderedmap.OrderedMap); !ok { + error := fmt.Sprintf("Type of first vslice element is not an ordered map. It appears to be '%v'\n", reflect.TypeOf(vslice[0])) + panic(error) + } + // Get the keys for the first element so we know what the column names will be + columnMap := vslice[0].(orderedmap.OrderedMap) + //fmt.Printf("First vslice element is an ordered map\n") + columnNames := columnMap.Keys() + // Check if xlsx file exists already, and if it does then open and append data if fileExists(outputFilename) { if overwriteFile { @@ -75,48 +168,6 @@ func main() { xlsx = createWorkbook(worksheetName, outputFilename) } - // Read the json input file - if fileExists(inputJson) { - s, err = os.ReadFile(inputJson) - if err != nil { - panic(err) - } - } else { - fmt.Printf("Input JSON file '%s' does not exist.\n", inputJson) - os.Exit(1) - } - - // Unmarshal the json into an orderedmap to preserve the ordering of json structure - o := orderedmap.New() - err = json.Unmarshal([]byte(s), &o) - if err != nil { - fmt.Printf("JSON Unmarshal error %s\n", err) - } - - // Assume that our content is within the first top-level key - topLevel := o.Keys() - fmt.Printf("Detected toplevel json key as: '%s'\n", topLevel[0]) - parentNode = topLevel[0] - - // Get a reference to the top level node we specified earlier - vislice, ok := o.Get(parentNode) - if !ok { - fmt.Printf("Missing key for multitype array") - } - - // Get an interface that we can work with to access the sub elements - vslice := vislice.([]interface{}) - - // Check that the first element is what we expected - if _, ok := vslice[0].(orderedmap.OrderedMap); !ok { - error := fmt.Sprintf("Type of first vslice element is not an ordered map. It appears to be '%v'\n", reflect.TypeOf(vslice[0])) - panic(error) - } - // Get the keys for the first element so we know what the column names will be - columnMap := vslice[0].(orderedmap.OrderedMap) - fmt.Printf("First vslice element is an ordered map") - columnNames := columnMap.Keys() - // Run code to add column names to the first row of the workbook createHeadingRow(xlsx, worksheetName, columnNames) @@ -186,23 +237,37 @@ func main() { // Each iteration should start back at column 1 column = 1 - // Print each key-value pair contained in this slice + // Get the key-value pairs contained in this slice vmap := v.(orderedmap.OrderedMap) k := vmap.Keys() - for j := range k { - //a = string(asciiValue) - //cell = a + strconv.Itoa(2+i) - cell, _ = excelize.CoordinatesToCellName(column, row) + if len(config.keyOrder) > 0 { + // If we have a specified order for the values then use that - e, _ := vmap.Get(k[j]) - //fmt.Printf("Setting cell %s to value %v\n", cell, e) - xlsx.SetCellValue(worksheetName, cell, e) + for j := 0; j < len(config.keyOrder); j++ { + cell, _ = excelize.CoordinatesToCellName(column, row) - // Move to the next column - //asciiValue++ - column++ + e, _ := vmap.Get(config.keyOrder[j]) + //fmt.Printf("Setting cell %s to value %v\n", cell, e) + xlsx.SetCellValue(worksheetName, cell, e) + + // Move to the next column + column++ + } + } else { + // Otherwise use the order the json was in + for j := range k { + cell, _ = excelize.CoordinatesToCellName(column, row) + + e, _ := vmap.Get(k[j]) + //fmt.Printf("Setting cell %s to value %v\n", cell, e) + xlsx.SetCellValue(worksheetName, cell, e) + + // Move to the next column + column++ + } } + //fmt.Printf("k: %v\n", k) // Move to next row @@ -327,14 +392,32 @@ func createHeadingRow(xlsx *excelize.File, worksheetName string, columnNames []s row := 1 column := 1 - // Add the header row - for i := 0; i < len(columnNames); i++ { - cell, _ = excelize.CoordinatesToCellName(column, row) - fmt.Printf("Setting cell %s to value %s\n", cell, columnNames[i]) - xlsx.SetCellValue(worksheetName, cell, columnNames[i]) - //xlsx.SetCellStyle(worksheetName, cell, cell, headerStyle) - column++ + if len(config.keyOrder) > 0 { + fmt.Printf("Setting heading order as per config key-order\n") + // Check that the number of specified columns matches input data + if len(config.keyOrder) != len(columnNames) { + error := fmt.Sprintf("Column order specified in json key-order but mismatch found in json data. %d specifed columns does not match %d found columns.", len(config.keyOrder), len(columnNames)) + panic(error) + } + + // Iterate the map and add the columns as per that order + for i := 0; i < len(config.keyOrder); i++ { + cell, _ = excelize.CoordinatesToCellName(column, row) + fmt.Printf("Setting cell %s to value %s at index %d\n", cell, config.keyOrder[i], i) + xlsx.SetCellValue(worksheetName, cell, config.keyOrder[i]) + column++ + } + } else { + // Add the header row + for i := 0; i < len(columnNames); i++ { + cell, _ = excelize.CoordinatesToCellName(column, row) + fmt.Printf("Setting cell %s to value %s\n", cell, columnNames[i]) + xlsx.SetCellValue(worksheetName, cell, columnNames[i]) + //xlsx.SetCellStyle(worksheetName, cell, cell, headerStyle) + column++ + } } + } // Taken from https://github.com/qax-os/excelize/issues/92#issuecomment-821578446 @@ -352,7 +435,7 @@ func SetColAutoWidth(xlsx *excelize.File, sheetName string) error { largestWidth = cellWidth } } - fmt.Printf("SetColAutoWidth calculated largest width is '%d'\n", largestWidth) + fmt.Printf("SetColAutoWidth calculated largest width for column index '%d' is '%d'\n", idx, largestWidth) name, err := excelize.ColumnNumberToName(idx + 1) if err != nil { return err diff --git a/internal/.DS_Store b/internal/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0