英文:
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
}
}
可能还有其他的结构。
我该如何“编辑”这样的动态结构?我为最简单的情况编写了这个“解析器”:
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 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论