英文:
Transform String into nested Json (Java)
问题
以下是翻译好的内容:
我想从你们这里得到一些指导,我在处理Java + Spring Boot的情况下感到困惑。
我从数据库中获得了2列字符串,第一列是由斜杠(/)分隔的路径,例如"crumbs[0]/link/path",第二列是分配给第一列的值,我尝试用这些数据创建一个嵌套的JSON。
例如,我从数据库中以前述的两列形式接收到以下响应:
列1(路径),列2(值)
"crumbs[0]/link/path","/pokemon/type/pokemon?lang=en"
"crumbs[0]/link/wid","tablePokemon"
"crumbs[0]/name","Pokemon"
"data/records[1]/id","Pikachu"
"data/records[1]/link/path":"/pokemon/type/eletric/pikachu"
"data/records[1]/link/wid":"tableEletric"
"data/records[1]/available":"true"
"data/records[2]/id":"Bulbasaur"
"data/records[2]/link/path":"/pokemon/type/grass/bulbasaur"
"data/records[2]/link/wid":"tableGrass"
"data/records[2]/available":"true"
从数据库中获取到这个响应后,我在Java中试图得到如下结果:
"crumbs":[
{
"link":{
"path":"/pokemon/type/pokemon?lang=en",
"wid":"tablePokemon"
},
"name":"Pokemon"
}
],
"data":{
"records":[
{
"id":"Pikachu",
"link":{
"path":"/pokemon/type/eletric/pikachu",
"wid":"tableEletric"
},
"available":"true",
},
{
"id":"Bulbasaur",
"link":{
"path":"/pokemon/type/grass/bulbasaur",
"wid":"tableGrass"
},
"available":"true",
}
]
}
你们有什么建议可以帮助我实现这个目标吗?
非常感谢你们的时间,非常感谢任何帮助。
英文:
I would like the guidence from you all, i'm confused in how to go on in a situation at Java + Spring Boot.
I receive from the database 2 columns of strings, the first column is a path separeted by a slash(/) like "crumbs[0]/link/path" and the second column have the value assigned to the first column, and what i'm trying to do is to create a nested JSON with this.
For example, i'm receiving from the database the following response in two columns like a said before:
COLUMN 1(PATH), COLUMN 2(VALUE)
"crumbs[0]/link/path", "/pokemon/type/pokemon?lang=en"
"crumbs[0]/link/wid", "tablePokemon",
"crumbs[0]/name", "Pokemon"
"data/records[1]/id", "Pikachu"
"data/records[1]/link/path": "/pokemon/type/eletric/pikachu",
"data/records[1]/link/wid": "tableEletric",
"data/records[1]/available": "true",
"data/records[2]/id", "Bulbasaur"
"data/records[2]/link/path": "/pokemon/type/grass/bulbasaur",
"data/records[2]/link/wid": "tableGrass",
"data/records[2]/available": "true",
With this response from database, i'm trying to get this result in Java:
"crumbs": [
{
"link": {
"path": "/pokemon/type/pokemon?lang=en",
"wid": "tablePokemon"
},
"name": "Pokemon"
}
],
"data": {
"records": [
{
"id": "Pikachu",
"link": {
"path": "/pokemon/type/eletric/pikachu",
"wid": "tableEletric"
},
"available": "true",
},
{
"id": "Bulbasaur",
"link": {
"path": "/pokemon/type/grass/bulbasaur",
"wid": "tableGrass"
},
"available": "true",
}
]
}
You guys would have any suggestions for me to achieve this objective?
Thank you all for your time, appreciate any help.
答案1
得分: 1
你可以轻松地使用 com.fasterxml.jackson.core.JsonPointer 构建一个 JSON!
有关解析 JsonPath 并从中构建 Json 的一些详细信息在这里提到:https://stackoverflow.com/questions/51971642/how-to-add-new-node-to-json-using-jsonpath
你可以利用上述引用中的代码来构建你的代码。将 com.fasterxml.jackson 依赖项添加到你的 pom.xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.2</version>
</dependency>
private static final ObjectMapper mapper = new ObjectMapper();
public static void main(String[] args) {
Map<String, String> databaseKeyValues = new HashMap<String, String>();
databaseKeyValues.put("crumbs[0]/link/path", "/pokemon/type/pokemon?lang=en");
databaseKeyValues.put("crumbs[0]/link/wid", "tablePokemon");
databaseKeyValues.put("crumbs[0]/name", "Pokemon");
databaseKeyValues.put("data/records[1]/id", "Pikachu");
// 其他的键值对...
ObjectNode rootNode = mapper.createObjectNode();
for(java.util.Map.Entry<String, String> e : databaseKeyValues.entrySet()) {
setJsonPointerValue(rootNode, JsonPointer.compile("/" + e.getKey()), new TextNode(e.getValue()));
}
try {
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode));
} catch (JsonProcessingException e1) {
e1.printStackTrace();
}
}
public static void setJsonPointerValue(ObjectNode node, JsonPointer pointer, JsonNode value) {
JsonPointer parentPointer = pointer.head();
JsonNode parentNode = node.at(parentPointer);
String fieldName = pointer.last().toString().substring(1);
if (parentNode.isMissingNode() || parentNode.isNull()) {
parentNode = mapper.createObjectNode();
setJsonPointerValue(node, parentPointer, parentNode);
}
if (parentNode.isArray()) {
ArrayNode arrayNode = (ArrayNode) parentNode;
int index = Integer.valueOf(fieldName);
for (int i = arrayNode.size(); i <= index; i++) {
arrayNode.addNull();
}
arrayNode.set(index, value);
} else if (parentNode.isObject()) {
((ObjectNode) parentNode).set(fieldName, value);
} else {
throw new IllegalArgumentException("`" + fieldName + "` can't be set for parent node `"
+ parentPointer + "` because parent is not a container but " + parentNode.getNodeType().name());
}
}
输出:
{
"data" : {
"records[1]" : {
"id" : "Pikachu",
"link" : {
"wid" : "tableEletric",
"path" : "/pokemon/type/eletric/pikachu"
},
"available" : "true"
},
"records[2]" : {
"available" : "true",
"link" : {
"wid" : "tableGrass",
"path" : "/pokemon/type/grass/bulbasaur"
},
"id" : "Bulbasaur"
}
},
"crumbs[0]" : {
"link" : {
"path" : "/pokemon/type/pokemon?lang=en",
"wid" : "tablePokemon"
},
"name" : "Pokemon"
}
}
一旦我们处理了从 "crumbs[0]/link/path" 到 "crumbs/0/link/path" 的 JsonPath,json 数组 "records[1]"、"records[2]" 和 "crumbs[0]" 将被解决。只需进行一些字符串操作(通过值迭代并替换 "[0]" 为 "/0/"),你可以编写一个正则表达式来进行匹配和替换!
英文:
You can easily construct a JSON with com.fasterxml.jackson.core.JsonPointer!
Some details on parsing a JsonPath and constructing a Json from it is mentioned here https://stackoverflow.com/questions/51971642/how-to-add-new-node-to-json-using-jsonpath
You could made use of the code from the above reference to build your code.
Add the com.fasterxml.jackson dependencies to your pom.xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.2</version>
</dependency>
private static final ObjectMapper mapper = new ObjectMapper();
public static void main(String[] args) {
/** I'm creating a below map to hold the values you have mentioned in the above case.
While using JsonPointer I found two issues with the key mentioned here
1. Key doesnt start with a / . I'm appending a / with the key while inserting to map
2. The arrays in data eg:crumbs[0]/link/path should be represented like crumbs/0/link/path ( I haven't handled this in the code, but it doesn't make much difference in the output)
**/
Map<String, String> databaseKeyValues = new HashMap<String, String>();
databaseKeyValues.put("crumbs[0]/link/path", "/pokemon/type/pokemon?lang=en");
databaseKeyValues.put("crumbs[0]/link/wid", "tablePokemon");
databaseKeyValues.put("crumbs[0]/name", "Pokemon");
databaseKeyValues.put("data/records[1]/id", "Pikachu");
databaseKeyValues.put("data/records[1]/link/path", "/pokemon/type/eletric/pikachu");
databaseKeyValues.put("data/records[1]/link/wid", "tableEletric");
databaseKeyValues.put("data/records[1]/available", "true");
databaseKeyValues.put("data/records[2]/id", "Bulbasaur");
databaseKeyValues.put("data/records[2]/link/path", "/pokemon/type/grass/bulbasaur");
databaseKeyValues.put("data/records[2]/link/wid", "tableGrass");
databaseKeyValues.put("data/records[2]/available", "true");
ObjectNode rootNode = mapper.createObjectNode();
for(java.util.Map.Entry<String, String> e:databaseKeyValues.entrySet()) {
setJsonPointerValue(rootNode, JsonPointer.compile("/"+e.getKey()), //Adding slash to identify it as the root element, since our source data didn't have proper key!
new TextNode(e.getValue()));
}
try {
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode));
} catch (JsonProcessingException e1) {
e1.printStackTrace();
}
}
public static void setJsonPointerValue(ObjectNode node, JsonPointer pointer, JsonNode value) {
JsonPointer parentPointer = pointer.head();
JsonNode parentNode = node.at(parentPointer);
String fieldName = pointer.last().toString().substring(1);
if (parentNode.isMissingNode() || parentNode.isNull()) {
parentNode = mapper.createObjectNode();
setJsonPointerValue(node,parentPointer, parentNode); // recursively reconstruct hierarchy
}
if (parentNode.isArray()) {
ArrayNode arrayNode = (ArrayNode) parentNode;
int index = Integer.valueOf(fieldName);
// expand array in case index is greater than array size (like JavaScript does)
for (int i = arrayNode.size(); i <= index; i++) {
arrayNode.addNull();
}
arrayNode.set(index, value);
} else if (parentNode.isObject()) {
((ObjectNode) parentNode).set(fieldName, value);
} else {
throw new IllegalArgumentException("`" + fieldName + "` can't be set for parent node `"
+ parentPointer + "` because parent is not a container but " + parentNode.getNodeType().name());
}
}
Output:
{
"data" : {
"records[1]" : {
"id" : "Pikachu",
"link" : {
"wid" : "tableEletric",
"path" : "/pokemon/type/eletric/pikachu"
},
"available" : "true"
},
"records[2]" : {
"available" : "true",
"link" : {
"wid" : "tableGrass",
"path" : "/pokemon/type/grass/bulbasaur"
},
"id" : "Bulbasaur"
}
},
"crumbs[0]" : {
"link" : {
"path" : "/pokemon/type/pokemon?lang=en",
"wid" : "tablePokemon"
},
"name" : "Pokemon"
}
}
The json arrays records[1], records[2], crumbs[0] would be sorted out once we handle the JsonPath from crumbs[0]/link/path to crumbs/0/link/path. Just some string operations would help (iterate through the values and replace '[0]' with '/0/', you could write a regex to pattern match and replace!).
答案2
得分: 0
你需要解析这些路径,然后在内存中构建某种树状对象,最后将你构建的树转换为 JSON。
以下是一些建议:
- 首先定义一个空的根元素。你可以使用一个
Map
。键将是字符串,值可以是字符串、列表或映射。 - 对于每个路径,使用斜杠 "/" 进行分割。
- 对于除了最后一个的每个路径元素,检查它是列表还是子树。你可以通过字符串末尾是否有
[n]
来区分。 - 为路径创建除了最后一个节点之外的所有中间节点。从根(一个
Map
)开始,如果在该名称下它还不存在,为每个元素添加一个List
或Map
。如果已经存在,请确保它是你所需的类型。对于List
,追加元素。对于Map
,创建一个子条目。 - 对于最后一个路径元素,将其添加为
String
。 - 对所有路径重复以上步骤以填充树。
- 当完成时,使用递归和
StringBuilders
的组合来构造输出字符串。或者,如果你只使用了字符串、映射和列表,也可以使用诸如 Jackson 这样的库来生成 JSON。
请注意,你没有关于列表长度的信息,因此这种转换将不可逆。
英文:
You will need to parse the paths, then build some kind of tree object in memory, and finally convert the tree that you built into JSON.
Here are some tips:
- Start by defining an empty root element. You can use a
Map
. Keys will be strings, values will be either strings, lists or maps. - For each path, split it by "/".
- For each path element except the last, check if it is a list or a subtree. You can distinguish this by the presence of
[n]
at the end of the string. - Create all intermediate nodes for the path except for the last one. Starting from root (which is a
Map
), add either aList
or aMap
for each element if it doesn't exist yet under that name. If it already exists, check that it is what you need it to be. In case ofList
, append the element. In case ofMap
, create a sub-entry. - For the last path element, add it as a
String
. - Repeat this for all paths to fill your tree.
- When you are finished, use a combination of recursion and
StringBuiders
to construct the output string. Alternatively, if you only used strings, maps and lists, you can also use a library such as Jackson to produce JSON.
Note that you don't have information about the length of the lists, so this conversion will not be reversible.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论