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

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

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

问题

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

  1. {
  2. "request": {
  3. "method": "GET",
  4. "url": "/some/thing"
  5. },
  6. "response": {
  7. "status": 200,
  8. "body": "Hello world!",
  9. "headers": {
  10. "Content-Type": "text/plain"
  11. }
  12. }
  13. }

但也可以是这样的:

  1. {
  2. "mappings": [
  3. {
  4. "request": {
  5. "method": "GET",
  6. "url": "/one"
  7. },
  8. "response": {
  9. "status": 200
  10. }
  11. },
  12. {
  13. "id": "8c5db8b0-2db4-4ad7-a99f-38c9b00da3f7",
  14. "request": {
  15. "url": "/two"
  16. },
  17. "response": {
  18. "status": 200,
  19. "body": "Body content"
  20. }
  21. }
  22. ],
  23. "importOptions": {
  24. "duplicatePolicy": "IGNORE",
  25. "deleteAllNotInImport": true
  26. }
  27. }

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

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

  1. package main
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "log"
  8. "net/http"
  9. )
  10. var anytype map[string]interface{}
  11. func parseMappings() {
  12. }
  13. func parseReq(req map[string]interface{}) (string, error) {
  14. fmt.Printf("%T %v\n", req, req)
  15. for k, v := range req {
  16. if k == "url" {
  17. if v, ok := v.(string); ok {
  18. return ("/geronimo" + v), nil
  19. }
  20. return "", errors.New("Not a string")
  21. }
  22. }
  23. return "", nil
  24. }
  25. func handler(w http.ResponseWriter, req *http.Request) {
  26. payload, err := io.ReadAll(req.Body)
  27. if err != nil {
  28. log.Fatal(err)
  29. }
  30. err = json.Unmarshal(payload, &anytype)
  31. if err != nil {
  32. log.Fatal(err)
  33. }
  34. fmt.Printf("%T %v\n", anytype, anytype)
  35. for k, v := range anytype {
  36. if k == "request" {
  37. if v, ok := v.(map[string]interface{}); ok {
  38. s, err := parseReq(v)
  39. if err != nil {
  40. log.Fatal(err)
  41. }
  42. // 在这里该怎么做?如何用新值替换URL?
  43. // url = s
  44. fmt.Println("Done", s)
  45. }
  46. } else {
  47. fmt.Printf("%v %T\n", k, v)
  48. }
  49. }
  50. }
  51. func main() {
  52. http.HandleFunc("/", handler)
  53. http.ListenAndServe(":8080", nil)
  54. }

但即使在这里,我也不知道如何用新数据替换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:

  1. {
  2. "request": {
  3. "method": "GET",
  4. "url": "/some/thing"
  5. },
  6. "response": {
  7. "status": 200,
  8. "body": "Hello world!",
  9. "headers": {
  10. "Content-Type": "text/plain"
  11. }
  12. }
  13. }

but also something like this:

  1. {
  2. "mappings": [
  3. {
  4. "request": {
  5. "method": "GET",
  6. "url": "/one"
  7. },
  8. "response": {
  9. "status": 200
  10. }
  11. },
  12. {
  13. "id": "8c5db8b0-2db4-4ad7-a99f-38c9b00da3f7",
  14. "request": {
  15. "url": "/two"
  16. },
  17. "response": {
  18. "status": 200,
  19. "body": "Body content"
  20. }
  21. }
  22. ],
  23. "importOptions": {
  24. "duplicatePolicy": "IGNORE",
  25. "deleteAllNotInImport": true
  26. }
  27. }

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:

  1. package main
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "log"
  8. "net/http"
  9. )
  10. var anytype map[string]interface{}
  11. func parseMappings() {
  12. }
  13. func parseReq(req map[string]interface{}) (string, error) {
  14. fmt.Printf("%T %v\n", req, req)
  15. for k, v := range req {
  16. if k == "url" {
  17. if v, ok := v.(string); ok {
  18. return ("/geronimo" + v), nil
  19. }
  20. return "", errors.New("Not a string")
  21. }
  22. }
  23. return "", nil
  24. }
  25. func handler(w http.ResponseWriter, req *http.Request) {
  26. payload, err := io.ReadAll(req.Body)
  27. if err != nil {
  28. log.Fatal(err)
  29. }
  30. err = json.Unmarshal(payload, &anytype)
  31. if err != nil {
  32. log.Fatal(err)
  33. }
  34. fmt.Printf("%T %v\n", anytype, anytype)
  35. for k, v := range anytype {
  36. if k == "request" {
  37. if v, ok := v.(map[string]interface{}); ok {
  38. s, err := parseReq(v)
  39. if err != nil {
  40. log.Fatal(err)
  41. }
  42. // what to do here? how replace url with new value?
  43. // url = s
  44. fmt.Println("Done", s)
  45. }
  46. } else {
  47. fmt.Printf("%v %T\n", k, v)
  48. }
  49. }
  50. }
  51. func main() {
  52. http.HandleFunc("/", handler)
  53. http.ListenAndServe(":8080", nil)
  54. }

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值的对象,并对其进行操作。可以像这样进行操作:

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

另外,你也可以使用现有的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:

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

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:

确定