I have a json array where it contains some flags as key and I have set the default values for those keys as false. this is my json array.
var flags = map[string]bool{
"terminationFlag": false,
"transferFlag": false,
"jrCancelledFlag": false,
"jrFilledFlag": false,
}
On performing an operation in a for loop, i have to update 1 field in the above json array as true. During the next iteration, it has to update the 2nd field in the json array as true. After all the fields in the json array is set to true, I have to return the json array.
the code i tried:
Keystrings := []string{"terminationReport - 2019-1","transferReport - 2019-1","jrCancelledReport - 2019-1","jrFilledReport - 2019-1"}
fmt.Println("Keystrings ", Keystrings)
for i,value := range Keystrings {
bytesread, err = stub.GetState(value)
var result []string
_ = json.Unmarshal(bytesread, &result)
fmt.Println("result ", result)
if result[0] == "yes"{
fmt.Println("result in if ", result)
flags[i] = true
}
}
Since it's very hard to understand from the question what is being asked, here's a simple attempt at working with similar data as the question, in the hope that you can take the right parts from this sample and adapt them to your issue. Follow the comments in the code to understand what's going on.
package main
import (
"encoding/json"
"fmt"
"log"
)
var jsonBlob = []byte(`["jrCancelledFlag", "yes"]`)
var flags = map[string]bool{
"terminationFlag": false,
"transferFlag": false,
"jrCancelledFlag": false,
"jrFilledFlag": false,
}
func main() {
// Parse jsonBlob into a slice of strings
var parsed []string
if err := json.Unmarshal(jsonBlob, &parsed); err != nil {
log.Fatalf("JSON unmarshal: %s", err)
}
// Expect the slice to be of length 2, first item flag name, second item
// yes/no.
if len(parsed) != 2 {
log.Fatalf("parsed len %d, expected 2", len(parsed))
}
// Assume parsed[0] actually appears in flags... otherwise more error checking
// is needed.
if parsed[1] == "yes" {
flags[parsed[0]] = true
}
// Emit updated flags as json
json, err := json.Marshal(flags)
if err != nil {
log.Fatalf("JSON marshal: %s", err)
}
fmt.Println(string(json))
}
This can be achieved cleaning by using the JSON interface to define your own unmarshaller
https://medium.com/#nate510/dynamic-json-umarshalling-in-go-88095561d6a0
package main
import (
"encoding/json"
"fmt"
"log"
)
var jsonBlob = []byte(`["jrCancelledFlag", "yes"]`)
// Flags ...
type Flags struct {
TerminationFlag bool `json:"terminationFlag,omitempty"`
TransferFlag bool `json:"transferFlag,omitempty"`
JRCancelledFlag bool `json:"jrCancelledFlag,omitempty"`
JRFilledFlag bool `json:"jrFilledFlag,omitempty"`
}
// UnmarshalJSON satisfies the JSON unmarshaller interface
func (f *Flags) UnmarshalJSON(data []byte) error {
var parsed []string
if err := json.Unmarshal(jsonBlob, &parsed); err != nil {
return err
}
if len(parsed)%2 != 0 {
return fmt.Errorf("expected string to be evenly paired")
}
for i := 0; i < len(parsed); i++ {
j := i + 1
if j < len(parsed) {
switch parsed[i] {
case "terminationFlag":
f.TerminationFlag = toBool(parsed[j])
case "transferFlag":
f.TransferFlag = toBool(parsed[j])
case "jrCancelledFlag":
f.JRCancelledFlag = toBool(parsed[j])
case "jrFilledFlag":
f.JRFilledFlag = toBool(parsed[j])
}
}
}
return nil
}
func toBool(s string) bool {
if s == "yes" {
return true
}
return false
}
func main() {
var flags Flags
err := json.Unmarshal(jsonBlob, &flags)
if err != nil {
log.Fatal(err)
}
b, _ := json.Marshal(flags)
fmt.Println(string(b))
}
I need to decode and encode strings using the gson format (it's a json dialect). Below is the code I came up with so far translated from the gson(Java) library
For some reasons none of the characters I try to decode/replace is actually replaced. I believe I'm doing something wrong with the character escaping(I'm new to go) so any direction/help to fix it would be appreciated.
Go Playground
package main
import (
"bytes"
"fmt"
"strings"
)
const s = `https:\/\/exampple.com\/static\/_\/js\/k\x3dgaia.gaiafe_glif.en.nnMHsIffkD4.O\/m\x3dglifb,identifier,unknownerror\/am\x3dggIgAAAAAAEKBCEImA2CYiCxoQo\/rt\x3dj\/d\x3d1\/rs\x3dABkqax3Fc8CWFtgWOYXlvHJI_bE3oVSwgA`
const des = `https://exampple.com/static/_/js/k=gaia.gaiafe_glif.en.nnMHsIffkD4.O/m=P9M9H,HUb4Ab,sy1m,sy1n,emo,sy1k,sy54,gsfs7c/am=ggIgAAAAAAEKBCEImA2CYiCxoQo/rt=j/d=0/rs=ABkqax3Fc8CWFtgWOYXlvHJI_bE3oVSwgA`
func main() {
dec, err := Decode(s, true)
if err != nil {
panic(err)
}
if dec != des {
fmt.Printf("expected \n %v \ngot \n %s", dec, des)
}
}
type replacementChar map[rune]string
func (r replacementChar) get(k rune) string {
return fmt.Sprintf("\\u%04x", r[k])
}
var replacement = replacementChar{
'"': "\\\"",
'\\': "\\\\",
'\t': "\\t",
'\b': "\\b",
'\n': "\\n",
'\r': "\\r",
'\f': "\\f",
}
var htmlReplacement = replacementChar{
'<': "\\u003c",
'>': "\\u003e",
'&': "\\u0026",
'=': "\\u003d",
'\'': "\\u0027",
}
var extraReplacement = replacementChar{
'\u2028': "\\u2028",
'\u2029': "\\u2029",
}
/*
* From RFC 7159, "All Unicode characters may be placed within the
* quotation marks except for the characters that must be escaped:
* quotation mark, reverse solidus, and the control characters
* (U+0000 through U+001F)."
*
* We also escape '\u2028' and '\u2029', which JavaScript interprets as
* newline characters. This prevents eval() from failing with a syntax
* error. http://code.google.com/p/google-gson/issues/detail?id=341
*/
func Encode(s string, htmlSafe bool) (string, error) {
buf := bytes.NewBuffer([]byte("\""))
var err error
for _, r := range s {
switch {
case replacement[r] != "":
_, err = buf.WriteString(replacement.get(r))
if err != nil {
return "", err
}
case htmlSafe && htmlReplacement[r] != "":
_, err = buf.WriteString(htmlReplacement.get(r))
if err != nil {
return "", err
}
case extraReplacement[r] != "":
_, err = buf.WriteString(extraReplacement.get(r))
if err != nil {
return "", err
}
default:
_, err = buf.WriteRune(r)
if err != nil {
return "", err
}
}
}
buf.WriteString("\"")
return buf.String(), nil
}
var decodeHTMLReplacementPair []string
var decodeReplacementPair []string
var decodeReplacementAll []string
func init() {
for k, _ := range htmlReplacement {
decodeHTMLReplacementPair = append(decodeHTMLReplacementPair, htmlReplacement.get(k))
decodeHTMLReplacementPair = append(decodeHTMLReplacementPair, string(k))
}
for k, _ := range replacement {
decodeReplacementPair = append(decodeReplacementPair, replacement.get(k))
decodeReplacementPair = append(decodeReplacementPair, string(k))
}
for k, _ := range extraReplacement {
decodeReplacementPair = append(decodeReplacementPair, extraReplacement.get(k))
decodeReplacementPair = append(decodeReplacementPair, string(k))
decodeHTMLReplacementPair = append(decodeHTMLReplacementPair, extraReplacement.get(k))
decodeHTMLReplacementPair = append(decodeHTMLReplacementPair, string(k))
}
decodeReplacementAll = append(decodeHTMLReplacementPair, decodeReplacementPair...)
}
func Decode(s string, htmlSafe bool) (string, error) {
var r *strings.Replacer
if !htmlSafe {
r = strings.NewReplacer(decodeHTMLReplacementPair...)
} else {
r = strings.NewReplacer(decodeReplacementAll...)
}
return r.Replace(s), nil
}
/* Original Java Source https://github.com/google/gson/blob/master/gson/src/main/java/com/google/gson/stream/JsonWriter.java
private static final String[] REPLACEMENT_CHARS;
private static final String[] HTML_SAFE_REPLACEMENT_CHARS;
static {
REPLACEMENT_CHARS = new String[128];
for (int i = 0; i <= 0x1f; i++) {
REPLACEMENT_CHARS[i] = String.format("\\u%04x", (int) i);
}
REPLACEMENT_CHARS['"'] = "\\\"";
REPLACEMENT_CHARS['\\'] = "\\\\";
REPLACEMENT_CHARS['\t'] = "\\t";
REPLACEMENT_CHARS['\b'] = "\\b";
REPLACEMENT_CHARS['\n'] = "\\n";
REPLACEMENT_CHARS['\r'] = "\\r";
REPLACEMENT_CHARS['\f'] = "\\f";
HTML_SAFE_REPLACEMENT_CHARS = REPLACEMENT_CHARS.clone();
HTML_SAFE_REPLACEMENT_CHARS['<'] = "\\u003c";
HTML_SAFE_REPLACEMENT_CHARS['>'] = "\\u003e";
HTML_SAFE_REPLACEMENT_CHARS['&'] = "\\u0026";
HTML_SAFE_REPLACEMENT_CHARS['='] = "\\u003d";
HTML_SAFE_REPLACEMENT_CHARS['\''] = "\\u0027";
}
private void string(String value) throws IOException {
String[] replacements = htmlSafe ? HTML_SAFE_REPLACEMENT_CHARS : REPLACEMENT_CHARS;
out.write("\"");
int last = 0;
int length = value.length();
for (int i = 0; i < length; i++) {
char c = value.charAt(i);
String replacement;
if (c < 128) {
replacement = replacements[c];
if (replacement == null) {
continue;
}
} else if (c == '\u2028') {
replacement = "\\u2028";
} else if (c == '\u2029') {
replacement = "\\u2029";
} else {
continue;
}
if (last < i) {
out.write(value, last, i - last);
}
out.write(replacement);
last = i + 1;
}
if (last < length) {
out.write(value, last, length - last);
}
out.write("\"");
}
*/
You are currently not replacing all kinds of escape combinations that would start with \, such as \/.
const s and des are not the same strings, no matter how you decode it
s does not contain a valid JSON encoded string as \x sequences are not valid.
Anyhow, since gson uses JSON (RFC 7159), I suggest using an existing package for this work. Try encoding/json:
func main() {
var dec string
err := json.Unmarshal([]byte(`"`+s+`"`), &dec)
if err != nil {
panic(err)
}
if dec != des {
fmt.Printf("expected \n %v \ngot \n %s", dec, des)
}
}
PS. The downvotes are most likely because your question can easily be considered code review, being more suitable for https://codereview.stackexchange.com
I'm a PHP Dev. But currently moving to Golang... I'm trying to retrieve data from a Form (Post method):
<!-- A really SIMPLE form -->
<form class="" action="/Contact" method="post">
<input type="text" name="Contact[Name]" value="Something">
<input type="text" name="Contact[Email]" value="Else">
<textarea name="Contact[Message]">For this message</textarea>
<button type="submit">Submit</button>
</form>
In PHP I would simple use this to get the data:
<?php
print_r($_POST["Contact"])
?>
// Output would be something like this:
Array
(
[Name] => Something
[Email] => Else
[Message] => For this message
)
BUT in go... either I get one by one or the whole thing but not the Contact[] Array only such as PHP
I thought about 2 solutions:
1) Get one by one:
// r := *http.Request
err := r.ParseForm()
if err != nil {
w.Write([]byte(err.Error()))
return
}
contact := make(map[string]string)
contact["Name"] = r.PostFormValue("Contact[Name]")
contact["Email"] = r.PostFormValue("Contact[Email]")
contact["Message"] = r.PostFormValue("Contact[Message]")
fmt.Println(contact)
// Output
map[Name:Something Email:Else Message:For this Message]
Note that the map keys are the whole: "Contact[Name]"...
2) Range whole map r.Form and "parse|obtain" those values with Prefix
"Contact[" and then replacing "Contact[" and "]" with empty string
so I can get the Form array Key only such the PHP Example
I went for this work around by my own but... ranging over the whole form may not be a good idea (?)
// ContactPost process the form sent by the user
func ContactPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
err := r.ParseForm()
if err != nil {
w.Write([]byte(err.Error()))
return
}
contact := make(map[string]string)
for i := range r.Form {
if strings.HasPrefix(i, "Contact[") {
rp := strings.NewReplacer("Contact[", "", "]", "")
contact[rp.Replace(i)] = r.Form.Get(i)
}
}
w.Write([]byte(fmt.Sprint(contact)))
}
//Output
map[Name:Something Email:Else Message:For this Message]
Both solutions give me the same output... But in the 2nd example I don't necessarily need to know the keys of "Contact[]"
I know... I may just forget about that "Form Array" and use name="Email" on my inputs and retrieve one by one but... I've passing through some scenarios where I use ONE form that contain more than 2 arrays of data and do different things with each one, like ORMs
Question 1: Is there a easier way to get my Form Array as an actual map in Golang like PHP does?
Question 2: Should I retrieve the data one by one (Tedious as much and I may change the Form data at some point and recompile...) or iterate the whole thing as I've done in the 2nd example.
Sorry for my bad English... Thanks in advance!
Is there a easier way to get my Form Array as an actual map in Golang like PHP does?
You can use the PostForm member of the http.Request type. It is of type url.Values -- which is actually (ta-da) a map[string][]string, and you can treat is as such. You'll still need to call req.ParseForm() first, though.
if err := req.ParseForm(); err != nil {
// handle error
}
for key, values := range req.PostForm {
// [...]
}
Note that PostForm is a map of lists of strings. That's because in theory, each field could be present multiple times in the POST body. The PostFormValue() method handles this by implicitly returning the first of multiple values (meaning, when your POST body is &foo=bar&foo=baz, then req.PostFormValue("foo") will always return "bar").
Also note that PostForm will never contain nested structures like you are used from PHP. As Go is statically typed, a POST form value will always be a mapping of string (name) to []string (value/s).
Personally, I wouldn't use the bracket syntax (contact[email]) for POST field names in Go applications; that's a PHP specific construct, anyway and as you've already noticed, Go does not support it very well.
Should I retrieve the data one by one (Tedious as much and I may change the Form data at some point and recompile...) or iterate the whole thing as I've done in the 2nd example.
There's probably no correct answer for that. If you are mapping your POST fields to a struct with static fields, you'll have to explicitly map them at some point (or use reflect to implement some magical auto-mapping).
I had a similar problem, so I wrote this function
func ParseFormCollection(r *http.Request, typeName string) []map[string]string {
var result []map[string]string
r.ParseForm()
for key, values := range r.Form {
re := regexp.MustCompile(typeName + "\\[([0-9]+)\\]\\[([a-zA-Z]+)\\]")
matches := re.FindStringSubmatch(key)
if len(matches) >= 3 {
index, _ := strconv.Atoi(matches[1])
for ; index >= len(result); {
result = append(result, map[string]string{})
}
result[index][matches[2]] = values[0]
}
}
return result
}
It turns a collection of form key value pairs into a list of string maps. For example, if I have form data like this:
Contacts[0][Name] = Alice
Contacts[0][City] = Seattle
Contacts[1][Name] = Bob
Contacts[1][City] = Boston
I can call my function passing the typeName of "Contacts":
for _, contact := range ParseFormCollection(r, "Contacts") {
// ...
}
And it will return a list of two map objects, each map containing keys for "Name" and "City". In JSON notation, it would look like this:
[
{
"Name": "Alice",
"City": "Seattle"
},
{
"Name": "Bob",
"City": "Boston"
}
]
Which incidentally, is exactly how I'm posting the data up to the server in an ajax request:
$.ajax({
method: "PUT",
url: "/api/example/",
dataType: "json",
data: {
Contacts: [
{
"Name": "Alice",
"City": "Seattle"
},
{
"Name": "Bob",
"City": "Boston"
}
]
}
})
If your form data key structure doesn't quite match mine, then I you could probably adapt the Regex that I'm using to suit your needs.
I had the same question. The submission of array form params is also idiomatic in the Ruby/Rails world where I'm coming from. But, after some research, it looks like this is not really the "Go-way".
I've been using the dot prefix convention: contact.name, contact.email, etc.
func parseFormHandler(writer http.ResponseWriter, request *http.Request) {
request.ParseForm()
userParams := make(map[string]string)
for key, _ := range request.Form {
if strings.HasPrefix(key, "contact.") {
userParams[string(key[8:])] = request.Form.Get(key)
}
}
fmt.Fprintf(writer, "%#v\n", userParams)
}
func main() {
server := http.Server{Addr: ":8088"}
http.HandleFunc("/", parseFormHandler)
server.ListenAndServe()
}
Running this server and then curling it:
$ curl -id "contact.name=Jeffrey%20Lebowski&contact.email=thedude#example.com&contact.message=I%20hate%20the%20Eagles,%20man." http://localhost:8088
Results in:
HTTP/1.1 200 OK
Date: Thu, 12 May 2016 16:41:44 GMT
Content-Length: 113
Content-Type: text/plain; charset=utf-8
map[string]string{"name":"Jeffrey Lebowski", "email":"thedude#example.com", "message":"I hate the Eagles, man."}
Using the Gorilla Toolkit
You can also use the Gorilla Toolkit's Schema Package to parse the form params into a struct, like so:
type Submission struct {
Contact Contact
}
type Contact struct {
Name string
Email string
Message string
}
func parseFormHandler(writer http.ResponseWriter, request *http.Request) {
request.ParseForm()
decoder := schema.NewDecoder()
submission := new(Submission)
err := decoder.Decode(submission, request.Form)
if err != nil {
log.Fatal(err)
}
fmt.Fprintf(writer, "%#v\n", submission)
}
Running this server and then curling it:
$ curl -id "Contact.Name=Jeffrey%20Lebowski&Contact.Email=thedude#example.com&Contact.Message=I%20hate%20the%20Eagles,%20man." http://localhost:8088
Results in:
HTTP/1.1 200 OK
Date: Thu, 12 May 2016 17:03:38 GMT
Content-Length: 128
Content-Type: text/plain; charset=utf-8
&main.Submission{Contact:main.Contact{Name:"Jeffrey Lebowski", Email:"thedude#example.com", Message:"I hate the Eagles, man."}}
I've been using the dot prefix convention: contact.name, contact.email
I decided to leave a script here so people don't have to spend so much time writing their own custom parser.
Here is a simple script that traverses the form data and puts the values in a struct that follows a format close to PHP and Ruby's.
package formparser
import (
"strings"
"mime/multipart"
)
type NestedFormData struct {
Value *ValueNode
File *FileNode
}
type ValueNode struct {
Value []string
Children map[string]*ValueNode
}
type FileNode struct {
Value []*multipart.FileHeader
Children map[string]*FileNode
}
func (fd *NestedFormData) ParseValues(m map[string][]string){
n := &ValueNode{
Children: make(map[string]*ValueNode),
}
for key, val := range m {
keys := strings.Split(key,".")
fd.nestValues(n, &keys, val)
}
fd.Value = n
}
func (fd *NestedFormData) ParseFiles(m map[string][]*multipart.FileHeader){
n := &FileNode{
Children: make(map[string]*FileNode),
}
for key, val := range m {
keys := strings.Split(key,".")
fd.nestFiles(n, &keys, val)
}
fd.File = n
}
func (fd *NestedFormData) nestValues(n *ValueNode, k *[]string, v []string) {
var key string
key, *k = (*k)[0], (*k)[1:]
if len(*k) == 0 {
if _, ok := n.Children[key]; ok {
n.Children[key].Value = append(n.Children[key].Value, v...)
} else {
cn := &ValueNode{
Value: v,
Children: make(map[string]*ValueNode),
}
n.Children[key] = cn
}
} else {
if _, ok := n.Children[key]; ok {
fd.nestValues(n.Children[key], k,v)
} else {
cn := &ValueNode{
Children: make(map[string]*ValueNode),
}
n.Children[key] = cn
fd.nestValues(cn, k,v)
}
}
}
func (fd *NestedFormData) nestFiles(n *FileNode, k *[]string, v []*multipart.FileHeader){
var key string
key, *k = (*k)[0], (*k)[1:]
if len(*k) == 0 {
if _, ok := n.Children[key]; ok {
n.Children[key].Value = append(n.Children[key].Value, v...)
} else {
cn := &FileNode{
Value: v,
Children: make(map[string]*FileNode),
}
n.Children[key] = cn
}
} else {
if _, ok := n.Children[key]; ok {
fd.nestFiles(n.Children[key], k,v)
} else {
cn := &FileNode{
Children: make(map[string]*FileNode),
}
n.Children[key] = cn
fd.nestFiles(cn, k,v)
}
}
}
Then you can use the package like so:
package main
import (
"MODULE_PATH/formparser"
"strconv"
"fmt"
)
func main(){
formdata := map[string][]string{
"contact.name": []string{"John Doe"},
"avatars.0.type": []string{"water"},
"avatars.0.name": []string{"Korra"},
"avatars.1.type": []string{"air"},
"avatars.1.name": []string{"Aang"},
}
f := &formparser.NestedFormData{}
f.ParseValues(formdata)
//then access form values like so
fmt.Println(f.Value.Children["contact"].Children["name"].Value)
fmt.Println(f.Value.Children["avatars"].Children[strconv.Itoa(0)].Children["name"].Value)
fmt.Println(f.Value.Children["avatars"].Children[strconv.Itoa(0)].Children["type"].Value)
fmt.Println(f.Value.Children["avatars"].Children[strconv.Itoa(1)].Children["name"].Value)
fmt.Println(f.Value.Children["avatars"].Children[strconv.Itoa(1)].Children["type"].Value)
//or traverse the Children in a loop
for key, child := range f.Value.Children {
fmt.Println("Key:", key, "Value:", child.Value)
if child.Children != nil {
for k, c := range child.Children {
fmt.Println(key + "'s child key:", k, "Value:", c.Value)
}
}
}
//if you want to access files do not forget to call f.ParseFiles()
}
I wrote some code, that transforms FormData array to json string.
package phprubyformdatatojson
import (
"bytes"
"io"
"net/url"
"strconv"
"strings"
)
type Node struct {
Name string
Value string
Subnodes []*Node
ArrayValue []*Node
}
func getJsonFromNode(rootNode *Node) string {
return "{" + nodeToJson(rootNode) + "}"
}
func nodeToJson(n *Node) string {
if len(n.Subnodes) == 0 && len(n.ArrayValue) == 0 {
return "\"" + n.Name + "\"" + ": " + "\"" + n.Value + "\""
}
if len(n.Subnodes) > 0 {
var parts []string
for _, subnode := range n.Subnodes {
parts = append(parts, nodeToJson(subnode))
}
if len(n.Name) > 0 {
return "\"" + n.Name + "\"" + ": {" + strings.Join(parts, ", ") + "}"
} else {
return strings.Join(parts, ", ")
}
}
if len(n.ArrayValue) > 0 {
var parts []string
for _, arrayPart := range n.ArrayValue {
parts = append(parts, "{"+nodeToJson(arrayPart)+"}")
}
return "\"" + n.Name + "\"" + ": [" + strings.Join(parts, ", ") + "]"
}
return "{}"
}
func addNode(nodeMap map[string]*Node, key string, value string) map[string]*Node {
keys := splitKeyToParts(key)
var lastNode *Node
previosKey := "rootNode"
totalKey := ""
for index, keyPart := range keys {
if totalKey == "" {
totalKey += keyPart
} else {
totalKey += "|||" + keyPart
}
isNumber := false
if _, err := strconv.Atoi(keyPart); err == nil {
isNumber = true
}
if index < len(keys)-1 {
if z, ok := nodeMap[totalKey]; !ok {
lastNode = z
node := &Node{}
nodeMap[totalKey] = node
lastNode = node
prevNode, oook := nodeMap[previosKey]
if oook {
if isNumber {
prevNode.ArrayValue = append(prevNode.ArrayValue, node)
} else {
node.Name = keyPart
prevNode.Subnodes = append(prevNode.Subnodes, node)
}
}
}
} else {
lastNode = nodeMap[previosKey]
newNode := &Node{Name: keyPart, Value: value}
if isNumber {
lastNode.ArrayValue = append(lastNode.ArrayValue, newNode)
} else {
lastNode.Subnodes = append(lastNode.Subnodes, newNode)
}
}
previosKey = totalKey
}
return nodeMap
}
func splitKeyToParts(key string) []string {
const DELIMITER = "|||||"
key = strings.Replace(key, "][", DELIMITER, -1)
key = strings.Replace(key, "[", DELIMITER, -1)
key = strings.Replace(key, "]", DELIMITER, -1)
key = strings.Trim(key, DELIMITER)
return strings.Split(key, DELIMITER)
}
func TransformMapToJsonString(source map[string][]string) string {
nodesMap := map[string]*Node{}
nodesMap["rootNode"] = &Node{}
for key, value := range source {
nodesMap = addNode(nodesMap, key, strings.Join(value, ""))
}
return getJsonFromNode(nodesMap["rootNode"])
}
When you can manualy transform you request and json.Unmarshal it, or write gin.Middleware
func PhpRubyArraysToJsonMiddleware(c *gin.Context) {
body, _ := c.GetRawData()
m, _ := url.ParseQuery(string(body))
parsedJson := TransformMapToJsonString(m)
newBody := []byte(parsedJson)
c.Request.Body = io.NopCloser(bytes.NewBuffer(newBody))
c.Next()
}
and use it like this
func handelUpdate(c *gin.Context) {
req := &YourJsonStruct{}
if err := c.BindJSON(req); err != nil {
c.Status(http.StatusBadRequest)
return
}
// your code
}
func main() {
router := gin.Default()
router.Use(PhpRubyArraysToJsonMiddleware)
router.POST("/update", handelUpdate)
}
I found something interesting in Go. Let's say I have my package name is mypkg, inside mypkg, I have two functions:
package mypkg
func MyFunc0(){
//...
}
var MyFunc1 = func(){
//...
}
Now in my main package, it is possible to override MyFunc1, like this:
mypkg.MyFunc1 = func(){
// new logic
}
However, it is not possible to override MyFunc0 the same way. So now a question is raised. What are the differences between the two ways of declaring a function? Is this behavior difference intended?
MyFunc0 is a function declaration (https://golang.org/ref/spec#Function_declarations)
MyFunc1 is not a function declaration. It is a variable (https://golang.org/ref/spec#Variable_declarations) of type func (see https://golang.org/ref/spec#Function_types, https://golang.org/ref/spec#Function_literals). It has an initial value, but can be changed to hold a different value/function (as long as function signatures match).
I learning go language (and English :P), and in the tour of go is a exersie: Fibonacci closure
(https://tour.golang.org/moretypes/22)
The result is:
0
1
1
2
3
5
8
13
21
34
The main function is:
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
And my first solution was:
func fibonacci() func() int {
antant := 0
ant := 1
i := 0
return func() int {
var result int
if i == 0 || i == 1 {
result = i
i++
return result
}
result = antant + ant
antant = ant
ant = result
return result
}
}
But I didn't want ask in heach call to f() if was the firsth or second call (if i == 0 || i == 1). The result was a function auto-override:
type doFibonacci func(*doFibonacci) int
func fibonacci() func() int {
antant := 0
ant := 1
i := 0
doFibo := doFibonacci(func(ptrDo *doFibonacci) int {
var result int
if i == 0 || i == 1 {
result = i
i++
return result
}
*ptrDo = func(ptrDo *doFibonacci) int {
var result int
result = antant + ant
antant = ant
ant = result
return result
}
return (*ptrDo)(ptrDo)
})
return func() int {
return doFibo(&doFibo)
}
}
I apologize for my English.