Inshort:我试图找到一些api,可以通过将第一个参数作为jsonString,第二个参数作为JSONPath来改变值,第三个参数将是该参数的新值。但是,我发现的只是这个...... https://code.google.com/p/json-path/
这个api允许我在JSON String中找到任何值。但是,我找不到简单的方法来更新任何键的值。例如,这是book.json。
{
"store":{
"book":[
{
"category":"reference",
"author":"Nigel Rees",
"title":"Sayings of the Century",
"price":8.95
},
{
"category":"fiction",
"author":"Evelyn Waugh",
"title":"Sword of Honour",
"price":12.99,
"isbn":"0-553-21311-3"
}
],
"bicycle":{
"color":"red",
"price":19.95
}
}
}
我可以通过这样做来获取自行车的颜色。
String bicycleColor = JsonPath.read(json, "$.store.bicycle.color");
但我正在寻找JsonPath或其他api中的一个方法,比如这个
JsonPath.changeNodeValue(json, "$.store.bicycle.color", "green");
String bicycleColor = JsonPath.read(json, "$.store.bicycle.color");
System.out.println(bicycleColor); // This should print "green" now.
我将这些选项排除在外,
原因:我对不同类型的服务有大约500个不同的请求,这些请求返回不同的json结构。所以,我不想总是手动创建新的JSON字符串。因为,ID在json结构中是动态的。
非常感谢任何想法或方向。
使用以下答案更新此问题。
复制此小片段并根据需要进行修改。
private static void updateJsonValue() {
JSONParser parser = new JSONParser();
JSONObject jsonObject = new JSONObject();
FileReader reader = null;
try {
File jsonFile = new File("path to book.json");
reader = new FileReader(jsonFile);
jsonObject = (JSONObject) parser.parse(reader);
} catch (Exception ex) {
System.out.println(ex.getLocalizedMessage());
}
Map<String, Object> userData = null;
try {
userData = new ObjectMapper().readValue(jsonObject.toJSONString(), Map.class);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
MutableJson json = new MutableJson(userData);
System.out.println("Before:\t" + json.map());
json.update("$.store.book[0].author", "jigish");
json.update("$.store.book[1].category", "action");
System.out.println("After:\t" + json.map().toString());
}
使用这些库。
答案 0 :(得分:9)
问题是你想要的功能已经是JsonPath的一个未记录的功能。使用json结构的示例:
String json = "{ \"store\":{ \"book\":[ { \"category\":\"reference\", \"author\":\"Nigel Rees\", \"title\":\"Sayings of the Century\", \"price\":8.95 }, { \"category\":\"fiction\", \"author\":\"Evelyn Waugh\", \"title\":\"Sword of Honour\", \"price\":12.99, \"isbn\":\"0-553-21311-3\" } ], \"bicycle\":{ \"color\":\"red\", \"price\":19.95 } } }";
DocumentContext doc = JsonPath.parse(json).
set("$.store.bicycle.color", "green").
set("$.store.book[0].price", 9.5);
String newJson = new Gson().toJson(doc.read("$"));
答案 1 :(得分:5)
假设已解析的JSON可以在内存中表示为Map,您可以构建类似于JsonPath的API,如下所示:
void update(Map<String, Object> json, String path, Object newValue);
我已经快速完成了对可以遍历json树的简单特定路径(不支持条件和通配符)的脏实现的要点,例如。 $ .store.name,$ .store.books [0] .isbn。这是:MutableJson.java。它肯定需要改进,但可以提供一个良好的开端。
用法示例:
import java.util.*;
public class MutableJson {
public static void main(String[] args) {
MutableJson json = new MutableJson(
new HashMap<String, Object>() {{
put("store", new HashMap<String, Object>() {{
put("name", "Some Store");
put("books", Arrays.asList(
new HashMap<String, Object>() {{
put("isbn", "111");
}},
new HashMap<String, Object>() {{
put("isbn", "222");
}}
));
}});
}}
);
System.out.println("Before:\t" + json.map());
json.update("$.store.name", "Book Store");
json.update("$.store.books[0].isbn", "444");
json.update("$.store.books[1].isbn", "555");
System.out.println("After:\t" + json.map());
}
private final Map<String, Object> json;
public MutableJson(Map<String, Object> json) {
this.json = json;
}
public Map<String, Object> map() {
return json;
}
public void update(String path, Object newValue) {
updateJson(this.json, Path.parse(path), newValue);
}
private void updateJson(Map<String, Object> data, Iterator<Token> path, Object newValue) {
Token token = path.next();
for (Map.Entry<String, Object> entry : data.entrySet()) {
if (!token.accept(entry.getKey(), entry.getValue())) {
continue;
}
if (path.hasNext()) {
Object value = token.value(entry.getValue());
if (value instanceof Map) {
updateJson((Map<String, Object>) value, path, newValue);
}
} else {
token.update(entry, newValue);
}
}
}
}
class Path {
public static Iterator<Token> parse(String path) {
if (path.isEmpty()) {
return Collections.<Token>emptyList().iterator();
}
if (path.startsWith("$.")) {
path = path.substring(2);
}
List<Token> tokens = new ArrayList<>();
for (String part : path.split("\\.")) {
if (part.matches("\\w+\\[\\d+\\]")) {
String fieldName = part.substring(0, part.indexOf('['));
int index = Integer.parseInt(part.substring(part.indexOf('[')+1, part.indexOf(']')));
tokens.add(new ArrayToken(fieldName, index));
} else {
tokens.add(new FieldToken(part));
}
};
return tokens.iterator();
}
}
abstract class Token {
protected final String fieldName;
Token(String fieldName) {
this.fieldName = fieldName;
}
public abstract Object value(Object value);
public abstract boolean accept(String key, Object value);
public abstract void update(Map.Entry<String, Object> entry, Object newValue);
}
class FieldToken extends Token {
FieldToken(String fieldName) {
super(fieldName);
}
@Override
public Object value(Object value) {
return value;
}
@Override
public boolean accept(String key, Object value) {
return fieldName.equals(key);
}
@Override
public void update(Map.Entry<String, Object> entry, Object newValue) {
entry.setValue(newValue);
}
}
class ArrayToken extends Token {
private final int index;
ArrayToken(String fieldName, int index) {
super(fieldName);
this.index = index;
}
@Override
public Object value(Object value) {
return ((List) value).get(index);
}
@Override
public boolean accept(String key, Object value) {
return fieldName.equals(key) && value instanceof List && ((List) value).size() > index;
}
@Override
public void update(Map.Entry<String, Object> entry, Object newValue) {
List list = (List) entry.getValue();
list.set(index, newValue);
}
}
使用Jackson可以很容易地将JSON字符串解析为Map:
Map<String,Object> userData = new ObjectMapper().readValue("{ \"store\": ... }", Map.class);
答案 2 :(得分:1)
回答将来登陆此页面的人员,以供参考。
您可以考虑使用jsonpatch的Java实现。可以找到RFC here
JSON Patch是一种用于描述JSON文档更改的格式。它可用于避免仅在部件发生更改时发送整个文档。当与HTTP PATCH方法结合使用时,它允许以符合标准的方式对HTTP API进行部分更新。
您可以指定需要执行的操作(替换,添加....),必须执行的json路径以及应该使用的值。
再次,从RFC中获取示例:
[
{ "op": "test", "path": "/a/b/c", "value": "foo" },
{ "op": "remove", "path": "/a/b/c" },
{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
{ "op": "replace", "path": "/a/b/c", "value": 42 },
{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
{ "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
]
对于Java实现,我自己没有使用它,但你可以尝试https://github.com/fge/json-patch
答案 3 :(得分:0)
因此,为了更改JSon字符串中的值,有两个步骤:
您正在尝试优化第2步,但要了解您无法避免第1步。查看Json路径源代码(实际上,它只是Jackson的包装器) ,请注意,在能够吐出读取值之前,它确实对Json字符串进行了完整的解析。每次拨打read()
时都会进行解析,例如它没有被缓存。
我认为这项任务非常具体,你必须自己编写。这就是我要做的事情:
String
部分。String
件的自定义序列化程序,以及您希望更改的数据我认为问题的确切范围非常不寻常,因此库不太可能存在。当程序收到Json String
时,大多数时候它想要的是完全反序列化的对象 - 它需要将此对象转发到其他地方是不常见的。