如何解决如何解析包含Java数组的Json
我有一个Json,其中包含Arrays的数组,现在我需要解析Json并计算元素,达到一定限制后,我需要将其放入结果Json。我能够解析到一个级别并计算元素。如何解析多个级别并以相同格式获取对象:
这是我尝试解析一个不包含元素数量的级别的示例代码:
private void handleJson(Object jsonObj,CountObject c,JSONObject jsonObj) {
Map<String,Object> map= new HashMap<>();
if (jsonObj instanceof JSONObject) {
parseJson(inputJSON,c,map,jsonObj);
}
}
}
private void parseJson(Object inputObj,Map<String,Object> map,JSONObject jsonObj) {
JSONObject nodeJson = (JSONObject) inputJSON;
Iterator<String> keyIter = nodeJson.keySet().iterator();
while (keyIter.hasNext()) {
String key = keyIter.next();
Object value = nodeJson.get(key);
if (value instanceof JSONObject) {
int offSet = c.getOffSet();
if(c.getLimit() == c.getOffSet()) {
break;
}
keyIter.remove();
map.put(key,value);
c.setOffSet(++offSet);;
} else {
handleJSONArray(value,k,key);
}
}
for (Entry<String,Object> entry : map.entrySet()) {
jsonObj.put(entry.getKey(),entry.getValue());
}
}
private void handleJSONArray(Object inputJSON,String key) {
JSONArray nodeJsonArr = (JSONArray) inputJSON;
int offSet = c.getOffSet();
List<Object> ll = new ArrayList<>();
for (int i = 0; i < nodeJsonArr.length(); i++) {
Object value = nodeJsonArr.get(i);
if (value instanceof JSONArray) {
handleJSONArray(value,key2);
} else {
if (k.getLimit() == k.getOffSet()) {
break;
}
ll.add(value);
++offSet;
}
}
map.put(key2,ll);
c.setOffSet(offSet);
}
这是我的Json:
{
"emails": [
{
"emails": [
{
"email": {
"id": "ac9e95cf-3338-4094-b465-e0e1deca23c4","value": "hello@gmail.com"
}
}
]
},{
"email": {
"id": "b61ffb48-ffc7-4ae6-81a2-78b632892fda","value": "hello1@gmail.com"
}
}
],"lastName": {
"id": "ffe19ece-819b-4680-8e0b-8566b34c973d","value": "FirstName"
},"firstName": {
"id": "4ed234f4-f679-40f3-b76b-41d9fdef7390","value": "LastName"
}
}
count对象是一个具有偏移量和Limit变量的Pojo,如果我将limit传递为3,那么我应该只获取前3个具有相同json格式的元素,如下所示:
{
"emails": [
{
"emails": [
{
"email": {
"id": "ac9e95cf-3338-4094-b465-e0e1deca23c4","value": "FirstName"
}
在这里我给出了一个示例JSON文件,并且Json可以包含任何数量的内部元素数组,逻辑应该能够解析任何类型的Json。 在这里,我还应该对Json元素进行分页,这意味着如果我通过offSet和limit,则应该相应地获取元素。在上面的示例中,CountObject包含limit和offSet,它基于该元素应获取元素。 要给出更多的解释,如果我将offSet设置为10并限制为10,则应该从第10个元素到第20个元素中提取元素,依此类推。
解决方法
这是使用Jackson的一种方法(我使用的是2.11.1版)。
此处的“ 项目”被定义为源JSON中的ID /值对之一,例如:
{
"id": "b61ffb48-ffc7-4ae6-81a2-78b632892fda","value": "hello1@gmail.com"
}
我将任务分为两部分:
-
通过删除后续项,在达到所需限制时切断数据。
-
清理所有生成的空对象或数组。
这是我的输入测试数据(基于问题中提供的数据):
private static final String JSON = "{\n"
+ " \"emails\": [{\n"
+ " \"emails\": [{\n"
+ " \"email\": {\n"
+ " \"id\": \"ac9e95cf-3338-4094-b465-e0e1deca23c4\",\n"
+ " \"value\": \"hello@gmail.com\"\n"
+ " }\n"
+ " }]\n"
+ " },\n"
+ " {\n"
+ " \"email\": {\n"
+ " \"id\": \"b61ffb48-ffc7-4ae6-81a2-78b632892fda\",\n"
+ " \"value\": \"hello1@gmail.com\"\n"
+ " }\n"
+ " }\n"
+ " ],\n"
+ " \"lastName\": {\n"
+ " \"id\": \"ffe19ece-819b-4680-8e0b-8566b34c973d\",\n"
+ " \"value\": \"LastName\"\n"
+ " },\n"
+ " \"firstName\": {\n"
+ " \"id\": \"4ed234f4-f679-40f3-b76b-41d9fdef7390\",\n"
+ " \"value\": \"FirstName\"\n"
+ " }\n"
+ "}";
代码:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.Iterator;
public class JsonReducer {
// get the first n "id/value" items:
private final int limit = 2;
// tracks how close we are to the cutoff limit:
private int counter = 0;
public void doParsing() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
JsonNode json = mapper.readValue(JSON,JsonNode.class);
// show the input JSON formatted,just for this demo:
System.out.println(json.toPrettyString());
// a copy of the original - we will use this when cleaning up:
JsonNode prevJson = json.deepCopy();
// remove unwanted items from the JSON
json = reduce(json);
// clean up empty nodes resulting from removals:
while (!json.equals(prevJson)) {
prevJson = json.deepCopy();
json = stripEmpty(json);
}
System.out.println("---------------------------------");
System.out.println(json.toPrettyString());
}
private JsonNode reduce(JsonNode json) {
for (JsonNode node : json) {
if (node.isObject()) {
counter++;
//System.out.println("obj " + counter + " - " + node.toString());
if (counter > limit) {
((ObjectNode) node).removeAll();
} else {
reduce(node);
}
} else if (node.isArray()) {
ArrayNode arrayNode = (ArrayNode) node;
//System.out.println("array - " + arrayNode.toString());
arrayNode.forEach((item) -> {
// assume each item is a JSON object - no arrays of arrays:
ObjectNode objectNode = (ObjectNode) item;
reduce(objectNode);
});
} //else if (node.isTextual()) {
//System.out.println("text - " + node.asText());
//}
}
return json;
}
private JsonNode stripEmpty(JsonNode json) {
Iterator<JsonNode> it = json.iterator();
while (it.hasNext()) {
JsonNode child = it.next();
if (child.isContainerNode() && child.isEmpty()) {
it.remove(); // remove empty arrays [],and objects {}
} else {
stripEmpty(child);
}
}
return json;
}
private static final String JSON = ... // as shown above.
}
reduce()
方法递归地遍历JSON,跟踪收集到的项目数量-然后删除超出所需数量的项目。
但是,这可能会在JSON中留下空的[]
数组或{}
对象,因此stripEmpty()
方法会对此进行处理。
因为我们要从上到下,从外到内依次遍历JSON,所以可能需要多次stripEmpty()
方法。可能有一种更有效的方法,只需要通过一次,但这至少是简单的方法。
结果示例:
对于限制= 2:
{
"emails" : [ {
"emails" : [ {
"email" : {
"id" : "ac9e95cf-3338-4094-b465-e0e1deca23c4","value" : "hello@gmail.com"
}
} ]
},{
"email" : {
"id" : "b61ffb48-ffc7-4ae6-81a2-78b632892fda","value" : "hello1@gmail.com"
}
} ]
}
对于限制= 1:
{
"emails" : [ {
"emails" : [ {
"email" : {
"id" : "ac9e95cf-3338-4094-b465-e0e1deca23c4","value" : "hello@gmail.com"
}
} ]
} ]
}
限制= 0:
{ }
附加点:
非通用
该方法假定在其他数组内直接嵌套任何数组-因此都没有:[ [ {...} ] ]
。换句话说,这不是100%的通用解析器,但确实与问题中的样本数据相符。
考虑使用POJO
此解决方案未定义将数据加载到其中的任何POJO Java对象-但这样做通常可以更轻松地获得所需的内容:
- 将数据加载(反序列化)到一个或多个POJO中。
- 从POJO中删除不需要的数据。
- 将剩余数据序列化回JSON。
如果该示例比问题中的示例更复杂,我想我愿意这样做,而不是仅操作JsonNode
数据。
更新
鉴于问题的变化,我认为我建议的最佳方法是将每个“ 项目”(请参见上面的定义)解析为一个POJO,该POJO仅包含3个字段:
String attribute;
String id;
String value;
执行此操作的代码如下:
private void traverse(JsonNode json) {
Iterator<Map.Entry<String,JsonNode>> it = json.fields();
while (it.hasNext()) {
Map.Entry<String,JsonNode> entry = it.next();
String name = entry.getKey();
JsonNode node = entry.getValue();
if (node.isArray()) {
ArrayNode arrayNode = (ArrayNode) node;
arrayNode.forEach((item) -> {
// assume each item is a JSON object - no arrays of arrays:
ObjectNode objectNode = (ObjectNode) item;
traverse(objectNode);
});
} else {
String id = node.get("id").asText();
String value = node.get("value").asText();
System.out.println("attr : " + name);
System.out.println("id : " + id);
System.out.println("value: " + value);
System.out.println("---");
}
}
}
您可以创建一个新的POJO实例,而不是println()
语句,并将其添加到ArrayList
中。
现在您有了一个包含所有数据的标准列表-您可以根据用户界面的需要访问项目1-100,然后101- 200 ...,依此类推。
您当然需要将原始POJO数据转换回UI需要/期望的任何格式。
使用问题中的示例JSON,上述方法将显示以下内容:
attr : email
id : ac9e95cf-3338-4094-b465-e0e1deca23c4
value: hello@gmail.com
---
attr : email
id : b61ffb48-ffc7-4ae6-81a2-78b632892fda
value: hello1@gmail.com
---
attr : lastName
id : ffe19ece-819b-4680-8e0b-8566b34c973d
value: LastName
---
attr : firstName
id : 4ed234f4-f679-40f3-b76b-41d9fdef7390
value: FirstName
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。