[英]Looking for Json-path/(any API) to update any value in given json string in Java
简而言之:我正在尝试找到一些可以通过将第一个参数作为jsonString,将第二个参数作为JSONPath并将第三个参数作为该参数的新值来更改值的api。 但是,我发现的只是这个。.https ://code.google.com/p/json-path/
这个API允许我在JSON字符串中查找任何值。 但是,我没有找到更新任何键值的简便方法。 例如,这是一个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()); }
使用这些库。
问题是所需的功能已经是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("$"));
假设已解析的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);
只是回答将来登陆此页面的人员以供参考。
您可以考虑使用jsonpatch的Java实现。 RFC可以在这里找到
JSON修补程序是一种描述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
因此,为了更改JSon字符串中的值,有两个步骤:
您正在尝试优化第2步,但了解到您将无法避免第1步。查看Json-path源代码(实际上,它只是Jackson的包装),请注意它确实做了在能够吐出读取值之前对Json字符串进行完整解析。 每次您调用read()
,它都会进行此解析,例如,它不会被缓存。
我认为这个任务足够具体,您将不得不自己编写它。 这是我会做的:
String
片段。 String
片段以及您希望更改的数据的自定义序列化程序 我认为您所遇到问题的确切范围非常不寻常,以至于不太可能为此存在一个库。 当程序接收到Json String
,大多数情况下它想要的是完全反序列化的对象-很少需要将这个对象转发到其他地方。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.