[英]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.