我需要解析任意json,编码/重写任何字符串键或超过85个字符的值(想想一种简短的URL服务)并将其编组回原始json。
例如像{"Name": "Ed", "Text": "long characters....85 chars"}
这样的文档应该像这样{"Name": "Ed", "Text": "short://ID=3403"}
。这个例子很简单,但我必须处理具有嵌套对象和数组以及基本未知结构的复杂结构。
我的问题是:是否可以使用已知库或甚至标准编码/ json包来执行此操作?
我实际需要的是相当于type string
上 package com.ama.ist.controller;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.ama.ist.model.CustomErrorType;
import com.ama.ist.model.Patch;
import com.ama.ist.service.PatchService;
@RestController
public class PatchController {
@Autowired
private PatchService patchService;
@CrossOrigin(origins = "http://ipnumber:portnumber")
@RequestMapping(value = "/mk", method = RequestMethod.POST)
public ResponseEntity<?> createFolder(@RequestBody Patch patch) {
System.out.println("patch ddest: => " + patch.getDestination());
String iscreatedstatus = patchService.create(patch);
System.out.println("iscreatedstatus" + iscreatedstatus);
if (!(iscreatedstatus.equals("Success"))) {
System.out.println("if success" );
return new ResponseEntity<Object>(new CustomErrorType("ER",iscreatedstatus), HttpStatus.NOT_FOUND);
}
System.out.println("if disinda success" );
return new ResponseEntity<Object>(new CustomErrorType("OK",iscreatedstatus), HttpStatus.CREATED);
}
//
@RequestMapping("/resource")
public Map<String,Object> home() {
Map<String,Object> model = new HashMap<String,Object>();
model.put("id", UUID.randomUUID().toString());
model.put("content", "Hello World");
return model;
}
}
接口的实现,但我们知道这是不可能的,所以我想知道我还有其他选择(除了分支标准之外) encoding / json包)
答案 0 :(得分:2)
是的,可以使用标准库和一些代码。
解组接口{}
var v interface{}
if err := json.Unmarshal(data, &v); err != nil {
// handle error
}
遍历解组的值,缩短字符串并重写:
func shorten(v interface{}) interface{} {
switch v := v.(type) {
case []interface{}:
for i, e := range v {
v[i] = shorten(e)
}
return v
case map[string]interface{}:
m := make(map[string]interface{})
for k, e := range v {
m[shortenString(k)] = shorten(e)
}
return m
case string:
return shortenString(v)
default:
return v
}
}
函数shorten
调用shortenString(s string) string
将长字符串转换为short://ID=xxx
。
将值重新编号为JSON:
p, err := json.Marshal(shorten(v))
if err != nil {
// handle error
}
// p is a []byte
fmt.Printf("%s\n", p)
答案 1 :(得分:1)
如果要求使用JSON中的新缩短版本替换所有超过85个字符的字符串,并且您可以假设JSON是有效的JSON(即,如果您不需要提供诊断)无效输入)然后您可以使用单个正则表达式替换。
有效JSON中的带引号的字符串可以与
匹配/"([^\\"]|\\.)*"/
因此,您可以使用可能缩短的版本替换此模式的所有实例。
答案 2 :(得分:0)
这是一种使用json.Decoder
Token()方法的方法(已测试),并避免将整个数据结构反序列化为内存。它主要是为了娱乐和为了说明如何使用该方法而完成的,但如果您的JSON文档非常大并且您希望避免内存开销,它可能会有所帮助。
// For example
r, w := os.Stdin, os.Stdout
dec := json.NewDecoder(r)
// Avoids any round-trip loss by leaving numbers un-parsed
dec.UseNumber()
// Current state (in an object or in an array; following the open
// delim, or a key, or a value). The decoder has its own stack pretty
// like this one, but it's private, so keep our own.
const (
jsonArrayStart = iota
jsonArrayVal
jsonObjectStart
jsonObjectKey
jsonObjectVal
)
stack := []byte{}
for {
t, err := dec.Token()
if err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
switch val := t.(type) {
case json.Delim:
// Copy delimiters out, and push/pop the state stack as appropriate
w.WriteString(string([]rune{rune(val)}))
switch val {
case '[':
stack = append(stack, jsonArrayStart)
case '{':
stack = append(stack, jsonObjectStart)
case ']', '}':
stack = stack[:len(stack)-1]
}
// The rest of the cases just copy values out
case nil:
w.WriteString("null")
case json.Number:
w.WriteString(string(val))
case bool:
if val {
w.WriteString("true")
} else {
w.WriteString("false")
}
case string:
// Modify strings if called for (shortenString needs to be provided)
if len(val) >= 85 {
val = shortenString(val)
}
encoded, err := json.Marshal(val)
if err != nil {
log.Fatal(err)
}
w.Write(encoded)
}
if dec.More() {
// If there's more in the current array/object, write a colon or comma
// (if we just wrote a key/value), and set the next state.
// Arrays start with a value, and follow with more values.
// Objects start with a key and alternate between key and value.
switch stack[len(stack)-1] {
case jsonArrayStart:
stack[len(stack)-1] = jsonArrayVal
case jsonArrayVal:
w.WriteString(",")
// State remains jsonArrayVal
case jsonObjectStart:
stack[len(stack)-1] = jsonObjectKey
case jsonObjectKey:
w.WriteString(":")
stack[len(stack)-1] = jsonObjectVal
case jsonObjectVal:
w.WriteString(",")
stack[len(stack)-1] = jsonObjectKey
}
} else {
if len(stack) == 0 {
// End after the first complete value (array/object) in the stream
break
}
if stack[len(stack)-1] == jsonObjectKey {
// Should never happen
log.Fatal("Object key without a value?")
}
}
}