How to "edit" "dynamic" json data with Go?

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

How to "edit" "dynamic" json data with Go?

问题

上次我在这里问如何在不知道数据结构的情况下编辑JSON数据,我被告知应该使用解组(unmarshal)而不是正则表达式,因为解组更高效。
我有一种类似于“服务器”的东西,它接收WireMock映射并稍作修改后发送回去。
WireMock映射可以有不同的结构-> https://wiremock.org/docs/stubbing/
它可以是这样的:

{
    "request": {
        "method": "GET",
        "url": "/some/thing"
    },
    "response": {
        "status": 200,
        "body": "Hello world!",
        "headers": {
            "Content-Type": "text/plain"
        }
    }
}

但也可以是这样的:

{
    "mappings": [
        {
            "request": {
                "method": "GET",
                "url": "/one"
            },
            "response": {
                "status": 200
            }
        },
        {
            "id": "8c5db8b0-2db4-4ad7-a99f-38c9b00da3f7",
            "request": {
                "url": "/two"
            },
            "response": {
                "status": 200,
                "body": "Body content"
            }
        }
    ],

    "importOptions": {
        "duplicatePolicy": "IGNORE",
        "deleteAllNotInImport": true
    }
}

可能还有其他的结构。 How to "edit" "dynamic" json data with Go?

我该如何“编辑”这样的动态结构?我为最简单的情况编写了这个“解析器”:

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
)

var anytype map[string]interface{}

func parseMappings() {

}

func parseReq(req map[string]interface{}) (string, error) {
	fmt.Printf("%T %v\n", req, req)
	for k, v := range req {
		if k == "url" {
			if v, ok := v.(string); ok {
				return ("/geronimo" + v), nil
			}
			return "", errors.New("Not a string")
		}
	}
	return "", nil

}

func handler(w http.ResponseWriter, req *http.Request) {
	payload, err := io.ReadAll(req.Body)
	if err != nil {
		log.Fatal(err)
	}
	err = json.Unmarshal(payload, &anytype)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%T %v\n", anytype, anytype)
	for k, v := range anytype {
		if k == "request" {
			if v, ok := v.(map[string]interface{}); ok {
				s, err := parseReq(v)
				if err != nil {
					log.Fatal(err)
				}
				// 在这里该怎么做?如何用新值替换URL?
				// url = s
				fmt.Println("Done", s)

			}
		} else {
			fmt.Printf("%v %T\n", k, v)
		}
	}

}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

但即使在这里,我也不知道如何用新数据替换URL的值
// 在这里该怎么做?如何用新值替换URL?
// url = s

英文:

Last time I asked here how to edit json data without knowing exact struct of that data and I was told to unmarshal it instead regexp because it's more efficient.
I have some kind of "server" which takes wiremock mapping changes it slightly and send back.
wiremock mapping can have different structs -> https://wiremock.org/docs/stubbing/
It can be something like this:

{
"request": {
"method": "GET",
"url": "/some/thing"
},
"response": {
"status": 200,
"body": "Hello world!",
"headers": {
"Content-Type": "text/plain"
}
}
}

but also something like this:

{
"mappings": [
{
"request": {
"method": "GET",
"url": "/one"
},
"response": {
"status": 200
}
},
{
"id": "8c5db8b0-2db4-4ad7-a99f-38c9b00da3f7",
"request": {
"url": "/two"
},
"response": {
"status": 200,
"body": "Body content"
}
}
],
"importOptions": {
"duplicatePolicy": "IGNORE",
"deleteAllNotInImport": true
}
}

and probably something else. How to "edit" "dynamic" json data with Go?

How can I "edit" such dynamic structure? I've written this "parser" for simplest case:

package main
import (
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"
)
var anytype map[string]interface{}
func parseMappings() {
}
func parseReq(req map[string]interface{}) (string, error) {
fmt.Printf("%T %v\n", req, req)
for k, v := range req {
if k == "url" {
if v, ok := v.(string); ok {
return ("/geronimo" + v), nil
}
return "", errors.New("Not a string")
}
}
return "", nil
}
func handler(w http.ResponseWriter, req *http.Request) {
payload, err := io.ReadAll(req.Body)
if err != nil {
log.Fatal(err)
}
err = json.Unmarshal(payload, &anytype)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%T %v\n", anytype, anytype)
for k, v := range anytype {
if k == "request" {
if v, ok := v.(map[string]interface{}); ok {
s, err := parseReq(v)
if err != nil {
log.Fatal(err)
}
// what to do here? how replace url with new value?
// url = s
fmt.Println("Done", s)
}
} else {
fmt.Printf("%v %T\n", k, v)
}
}
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}

but even here I have no idea how to replace url value with new data
// what to do here? how replace url with new value?
// url = s

答案1

得分: 2

如果你想替换输入中的URL值,你需要找到包含该URL值的对象,并对其进行操作。可以像这样进行操作:

req := m["request"]
if reqMap, ok := req.(map[string]interface{}); ok {
   // reqMap 是 "request: {...}" 中的对象
   reqMap["url"] = newURL
}

另外,你也可以使用现有的JSONPath库来实现。

英文:

If you want to replace a URL value in such an input, you have to find the object that contains that URL value, and work with that. Something like this:

req:=m["request"]
if reqMap, ok:=req.(map[string]interface{}); ok {
// reqMap is the object in "request: {...}"
reqMap["url"]=newURL
}

Alternatively, you can use one of the JSONPath libraries out there.

huangapple
  • 本文由 发表于 2023年3月23日 02:42:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/75816138.html
匿名

发表评论

匿名网友

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

确定