使用嵌套对象访问 jsonpath 元素
Accessing jsonpath elements with nested objects
我希望从数组和对象的 JSON 路径中提取某些值,并将这些值用于进一步处理,但我正在努力访问这些元素。这是 JSON 响应:
[
{
"od_pair":"7015400:8727100",
"buckets":[
{
"bucket":"C00",
"original":2,
"available":2
},
{
"bucket":"A01",
"original":76,
"available":0
},
{
"bucket":"B01",
"original":672,
"available":480
}
]
},
{
"od_pair":"7015400:8814001",
"buckets":[
{
"bucket":"C00",
"original":2,
"available":2
},
{
"bucket":"A01",
"original":40,
"available":40
},
{
"bucket":"B01",
"original":672,
"available":672
},
{
"bucket":"B03",
"original":632,
"available":632
},
{
"bucket":"B05",
"original":558,
"available":558
}
]
}
]
我尝试使用 $ 访问根元素,但我无法进一步使用它。
这是我写的测试方法。我想提取 od_pair 的值,并且在每个 od_pair 中,我需要能够检索存储桶代码及其可用编号。
public static void updateBuckets(String ServiceName, String DateOfJourney) throws Exception {
File jsonExample = new File(System.getProperty("user.dir"), "\LogAvResponse\LogAvResponse.json");
JsonPath jsonPath = new JsonPath(jsonExample);
List<Object> LegList = jsonPath.getList("$");
// List<HashMap<String, String>> jsonObjectsInArray = jsonPath.getList("$");
int NoofLegs = LegList.size();
System.out.println("No of legs :" + NoofLegs);
for (int j = 0; j <= NoofLegs; j++)
// for (HashMap<String, String> jsonObject : jsonObjectsInArray) {
{
String OD_Pair = jsonPath.param("j", j).getString("[j].od_pair");
// String OD_Pair = jsonObject.get("od_pair");
System.out.println("OD Pair: " + OD_Pair);
List<Object> BucketsList = jsonPath.param("j", j).getList("[j].buckets");
int NoOfBuckets = BucketsList.size();
// System.out.println("OD Pair: " + OD_Pair);
System.out.println("no of Buckets: " + NoOfBuckets);
for (int i = 0; i < NoOfBuckets; i++) {
String BucketCode = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].bucket");
String Available = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].available");
int BucketCodeColumn = XLUtils.getBucketCodeColumn(BucketCode);
int ServiceRow = XLUtils.getServiceRow(ServiceName, DateOfJourney, OD_Pair);
System.out.println("Row of " + ServiceName + ":" + DateOfJourney + "is:" + ServiceRow);
System.out.println("Bucket Code column of " + BucketCode + " is: " + BucketCodeColumn);
XLUtils.updateAvailability(ServiceRow, BucketCodeColumn, Available);
}
}
}
}
这是我看到的错误:
Caused by:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup
failed:
Script1.groovy: 1: unexpected token: [ @ line 1, column 27.
restAssuredJsonRootObject.[j].od_pair
有人可以帮我吗?
我建议将您的 JSON 解析为 Java classes 以简化处理过程。
怎么做?
首先,我们需要创建 Java classes 来表示您提供的 JSON。
我们来分析一下JSON。
以数组开头。该数组包含多个 JSON 对象。这些对象包含 od_pair
值和名为 buckets
.
的对象数组
让我们创建一个class(你可以随意命名)Pair
public class Pair {
public String od_pair; //this name is important because it corresponds with the json element's name!
public List<BucketObject> buckets; //same here!
}
此 class 表示主数组中的单个 JSON 对象。它包含 od_pair
值和嵌套的 JSON 数组,但在 Java 表示中 -> BucketObject
class 列表。让我们创建 BucketObject
class:
public class BucketObject { //this name is NOT importnat
public String bucket; //names are important
public int original;
public int available;
}
我们在每个对象中只有 3 个值。
现在,是时候将 JSON 解析为书面的 classes 了。
JsonPath path = JsonPath.from(json);
Pair[] pairs = path.getObject("$", Pair[].class);
请记住 Pair
是一个单独的 JSON 对象。这就是为什么我们从美元符号 $
表示的根开始解析,并且我们声明 JSON 应该被解析为一个包含 Pair
个对象的数组!
现在,处理会简单很多!
我不确定你需要什么,但我会向你展示如何根据 od_pair
字段从桶中获取数据的示例,你应该能够弄清楚其余的处理过程.
所以,我们有 Pair class 的数组:Pair[] pairs
;
现在,我们要根据 od_pair
值获得 1 个 Pair 对象。
public static Pair getPairBasedOnOdPairValue(Pair[] pairs, String odPairValue) {
for (Pair pair : pairs) {
if (pair.od_pair.equals(odPairValue)) return pair;
}
throw new NoSuchElementException();
}
现在,我们有了 Pair
对象。我们可以使用
访问此对象的 buckets
List<BucketObject> buckets = pair.buckets;
处理的其余部分是遍历 List<BucketObject>
并获得所需的值。
希望对您有所帮助!
OP 让我建议如何修复他的代码,因此是第二个答案。
让我们分析一下您提供的代码:
public static void updateBuckets(String ServiceName, String DateOfJourney) throws Exception {
File jsonExample = new File(System.getProperty("user.dir"), "\LogAvResponse\LogAvResponse.json");
JsonPath jsonPath = new JsonPath(jsonExample);
List<Object> LegList = jsonPath.getList("$");
// List<HashMap<String, String>> jsonObjectsInArray = jsonPath.getList("$");
int NoofLegs = LegList.size();
System.out.println("No of legs :" + NoofLegs);
for (int j = 0; j <= NoofLegs; j++)
// for (HashMap<String, String> jsonObject : jsonObjectsInArray) {
{
String OD_Pair = jsonPath.param("j", j).getString("[j].od_pair");
// String OD_Pair = jsonObject.get("od_pair");
System.out.println("OD Pair: " + OD_Pair);
List<Object> BucketsList = jsonPath.param("j", j).getList("[j].buckets");
int NoOfBuckets = BucketsList.size();
// System.out.println("OD Pair: " + OD_Pair);
System.out.println("no of Buckets: " + NoOfBuckets);
for (int i = 0; i < NoOfBuckets; i++) {
String BucketCode = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].bucket");
String Available = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].available");
int BucketCodeColumn = XLUtils.getBucketCodeColumn(BucketCode);
int ServiceRow = XLUtils.getServiceRow(ServiceName, DateOfJourney, OD_Pair);
System.out.println("Row of " + ServiceName + ":" + DateOfJourney + "is:" + ServiceRow);
System.out.println("Bucket Code column of " + BucketCode + " is: " + BucketCodeColumn);
XLUtils.updateAvailability(ServiceRow, BucketCodeColumn, Available);
}
}
}
我现在没有使用编译器,所以我可能会遗漏一些东西。
#1
我首先看到的是您将主数组保存到 List<Object>
List<Object> LegList = jsonPath.getList("$");
相反,您可以将它保存为更易于理解的类型,因为 Object 是如此通用,您不知道它里面有什么。
List<HashMap<String, Object>> LegList = jsonPath.getList("$");
#2
由于计算器,for
循环看起来不正确
j <= NoofLegs;
。
这可能会导致 IndexArrayOutOfBoundsException
或类似的情况。使用给定的代码,如果您有 4 条腿,for
循环将尝试处理 5 条不正确的腿。
#3
类似于 #1,保存遗愿清单的行
List<Object> BucketsList = jsonPath.param("j", j).getList("[j].buckets");
也可以改为 List<HashMap<String, Object>>
。
如果你这样做,你就不需要基于整数的嵌套 for
循环。
你看,HashMap<String, Object>
实际上对解析嵌套对象至关重要。字符串只是一个名称,如 buckets
或 od_pair
。这是 JSON 表示。第二个参数 Object
不同。 RestAssured returns HashMap 中的不同类型,这就是我们使用 Object
而不是 String
的原因。有时它不是字符串。
示例基于您的JSON:
将桶收集到 HashMap 列表:
List<HashMap<String, Object>> bucketsList = jsonPath.param("j", j).getList("[j].buckets");
列表中的每个 HashMap 都是这样的表示:
{
"bucket":"C00",
"original":2,
"available":2
},
HashMap
中的 Object
在您的情况下是 String
或 Integer
。
因此,如果您从 HashMap
中获取元素 bucket
,您将获取其值。
让我们将其与 for
循环结合起来进一步说明:
List<HashMap<String, Object>> bucketsList = jsonPath.param("j", j).getList("[j].buckets");
for (HashMap<String, Object> singleBucket : bucketsList) {
String firstValue = (String) singleBucket.get("bucket");
Integer secondValue = (Integer) singleBucket.get("original");
}
看错误信息,好像你用的是rest-assured,而JsonPath
class是来自放心库的io.restassured.path.json.JsonPath
。
我相信您知道,但是(可能对其他读者而言)请注意,这与 Jayway's json-path 不同,并且不是该库中的 com.jayway.jsonpath.JsonPath
class。
另请注意,如 manipulating/extracting JSON 的 documentation rest-assured uses the Groovy GPath 语法中所述。
这样,我相信以下内容将提取您需要的内容,即 od_pair 及其相应的可用数字桶:
Map<String, Map<String, Integer>> map = JsonPath.with(jsonString).get("collectEntries{entry -> [entry.od_pair, entry.buckets.collectEntries{bucketEntry -> [bucketEntry.bucket, bucketEntry.available]}]}");
对于映射的每个条目,键是 od_pair,值是另一个映射,其键是桶,值是可用数量。 jsonString
是您在问题中提供的 JSON。
您可以遍历地图以获得您想要的内容:
for(Map.Entry<String, Map<String, Integer>> entry : map.entrySet())
{
String od_pair = entry.getKey();
Map<String, Integer> bucketMap = entry.getValue();
for(Map.Entry<String, Integer> bucketEntry : bucketMap.entrySet())
{
String bucket = bucketEntry.getKey();
int available = bucketEntry.getValue();
}
}
打印地图你会得到:
{7015400:8727100={C00=2, A01=0, B01=480}, 7015400:8814001={C00=2, A01=40, B01=672, B03=632, B05=558}}
使用 Gson 将地图打印为 JSON:
System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(map));
你会得到
{
"7015400:8727100": {
"C00": 2,
"A01": 0,
"B01": 480
},
"7015400:8814001": {
"C00": 2,
"A01": 40,
"B01": 672,
"B03": 632,
"B05": 558
}
}
对于背景,字符串 collectEntries{entry -> [entry.od_pair, entry.buckets.collectEntries{bucketEntry -> [bucketEntry.bucket, bucketEntry.available]}]}
是一个 Groovy 闭包,它使用 Groovy 集合中的方法 API:参考 Collection, List and Map
向@Fenio 大声喊出上述纯 Java 解决方案。
我希望从数组和对象的 JSON 路径中提取某些值,并将这些值用于进一步处理,但我正在努力访问这些元素。这是 JSON 响应:
[
{
"od_pair":"7015400:8727100",
"buckets":[
{
"bucket":"C00",
"original":2,
"available":2
},
{
"bucket":"A01",
"original":76,
"available":0
},
{
"bucket":"B01",
"original":672,
"available":480
}
]
},
{
"od_pair":"7015400:8814001",
"buckets":[
{
"bucket":"C00",
"original":2,
"available":2
},
{
"bucket":"A01",
"original":40,
"available":40
},
{
"bucket":"B01",
"original":672,
"available":672
},
{
"bucket":"B03",
"original":632,
"available":632
},
{
"bucket":"B05",
"original":558,
"available":558
}
]
}
]
我尝试使用 $ 访问根元素,但我无法进一步使用它。
这是我写的测试方法。我想提取 od_pair 的值,并且在每个 od_pair 中,我需要能够检索存储桶代码及其可用编号。
public static void updateBuckets(String ServiceName, String DateOfJourney) throws Exception {
File jsonExample = new File(System.getProperty("user.dir"), "\LogAvResponse\LogAvResponse.json");
JsonPath jsonPath = new JsonPath(jsonExample);
List<Object> LegList = jsonPath.getList("$");
// List<HashMap<String, String>> jsonObjectsInArray = jsonPath.getList("$");
int NoofLegs = LegList.size();
System.out.println("No of legs :" + NoofLegs);
for (int j = 0; j <= NoofLegs; j++)
// for (HashMap<String, String> jsonObject : jsonObjectsInArray) {
{
String OD_Pair = jsonPath.param("j", j).getString("[j].od_pair");
// String OD_Pair = jsonObject.get("od_pair");
System.out.println("OD Pair: " + OD_Pair);
List<Object> BucketsList = jsonPath.param("j", j).getList("[j].buckets");
int NoOfBuckets = BucketsList.size();
// System.out.println("OD Pair: " + OD_Pair);
System.out.println("no of Buckets: " + NoOfBuckets);
for (int i = 0; i < NoOfBuckets; i++) {
String BucketCode = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].bucket");
String Available = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].available");
int BucketCodeColumn = XLUtils.getBucketCodeColumn(BucketCode);
int ServiceRow = XLUtils.getServiceRow(ServiceName, DateOfJourney, OD_Pair);
System.out.println("Row of " + ServiceName + ":" + DateOfJourney + "is:" + ServiceRow);
System.out.println("Bucket Code column of " + BucketCode + " is: " + BucketCodeColumn);
XLUtils.updateAvailability(ServiceRow, BucketCodeColumn, Available);
}
}
}
}
这是我看到的错误:
Caused by:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup
failed:
Script1.groovy: 1: unexpected token: [ @ line 1, column 27.
restAssuredJsonRootObject.[j].od_pair
有人可以帮我吗?
我建议将您的 JSON 解析为 Java classes 以简化处理过程。
怎么做? 首先,我们需要创建 Java classes 来表示您提供的 JSON。
我们来分析一下JSON。
以数组开头。该数组包含多个 JSON 对象。这些对象包含 od_pair
值和名为 buckets
.
让我们创建一个class(你可以随意命名)Pair
public class Pair {
public String od_pair; //this name is important because it corresponds with the json element's name!
public List<BucketObject> buckets; //same here!
}
此 class 表示主数组中的单个 JSON 对象。它包含 od_pair
值和嵌套的 JSON 数组,但在 Java 表示中 -> BucketObject
class 列表。让我们创建 BucketObject
class:
public class BucketObject { //this name is NOT importnat
public String bucket; //names are important
public int original;
public int available;
}
我们在每个对象中只有 3 个值。
现在,是时候将 JSON 解析为书面的 classes 了。
JsonPath path = JsonPath.from(json);
Pair[] pairs = path.getObject("$", Pair[].class);
请记住 Pair
是一个单独的 JSON 对象。这就是为什么我们从美元符号 $
表示的根开始解析,并且我们声明 JSON 应该被解析为一个包含 Pair
个对象的数组!
现在,处理会简单很多!
我不确定你需要什么,但我会向你展示如何根据 od_pair
字段从桶中获取数据的示例,你应该能够弄清楚其余的处理过程.
所以,我们有 Pair class 的数组:Pair[] pairs
;
现在,我们要根据 od_pair
值获得 1 个 Pair 对象。
public static Pair getPairBasedOnOdPairValue(Pair[] pairs, String odPairValue) {
for (Pair pair : pairs) {
if (pair.od_pair.equals(odPairValue)) return pair;
}
throw new NoSuchElementException();
}
现在,我们有了 Pair
对象。我们可以使用
buckets
List<BucketObject> buckets = pair.buckets;
处理的其余部分是遍历 List<BucketObject>
并获得所需的值。
希望对您有所帮助!
OP 让我建议如何修复他的代码,因此是第二个答案。
让我们分析一下您提供的代码:
public static void updateBuckets(String ServiceName, String DateOfJourney) throws Exception {
File jsonExample = new File(System.getProperty("user.dir"), "\LogAvResponse\LogAvResponse.json");
JsonPath jsonPath = new JsonPath(jsonExample);
List<Object> LegList = jsonPath.getList("$");
// List<HashMap<String, String>> jsonObjectsInArray = jsonPath.getList("$");
int NoofLegs = LegList.size();
System.out.println("No of legs :" + NoofLegs);
for (int j = 0; j <= NoofLegs; j++)
// for (HashMap<String, String> jsonObject : jsonObjectsInArray) {
{
String OD_Pair = jsonPath.param("j", j).getString("[j].od_pair");
// String OD_Pair = jsonObject.get("od_pair");
System.out.println("OD Pair: " + OD_Pair);
List<Object> BucketsList = jsonPath.param("j", j).getList("[j].buckets");
int NoOfBuckets = BucketsList.size();
// System.out.println("OD Pair: " + OD_Pair);
System.out.println("no of Buckets: " + NoOfBuckets);
for (int i = 0; i < NoOfBuckets; i++) {
String BucketCode = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].bucket");
String Available = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].available");
int BucketCodeColumn = XLUtils.getBucketCodeColumn(BucketCode);
int ServiceRow = XLUtils.getServiceRow(ServiceName, DateOfJourney, OD_Pair);
System.out.println("Row of " + ServiceName + ":" + DateOfJourney + "is:" + ServiceRow);
System.out.println("Bucket Code column of " + BucketCode + " is: " + BucketCodeColumn);
XLUtils.updateAvailability(ServiceRow, BucketCodeColumn, Available);
}
}
}
我现在没有使用编译器,所以我可能会遗漏一些东西。
#1
我首先看到的是您将主数组保存到 List<Object>
List<Object> LegList = jsonPath.getList("$");
相反,您可以将它保存为更易于理解的类型,因为 Object 是如此通用,您不知道它里面有什么。
List<HashMap<String, Object>> LegList = jsonPath.getList("$");
#2
由于计算器,for
循环看起来不正确
j <= NoofLegs;
。
这可能会导致 IndexArrayOutOfBoundsException
或类似的情况。使用给定的代码,如果您有 4 条腿,for
循环将尝试处理 5 条不正确的腿。
#3
类似于 #1,保存遗愿清单的行
List<Object> BucketsList = jsonPath.param("j", j).getList("[j].buckets");
也可以改为 List<HashMap<String, Object>>
。
如果你这样做,你就不需要基于整数的嵌套 for
循环。
你看,HashMap<String, Object>
实际上对解析嵌套对象至关重要。字符串只是一个名称,如 buckets
或 od_pair
。这是 JSON 表示。第二个参数 Object
不同。 RestAssured returns HashMap 中的不同类型,这就是我们使用 Object
而不是 String
的原因。有时它不是字符串。
示例基于您的JSON:
将桶收集到 HashMap 列表:
List<HashMap<String, Object>> bucketsList = jsonPath.param("j", j).getList("[j].buckets");
列表中的每个 HashMap 都是这样的表示:
{
"bucket":"C00",
"original":2,
"available":2
},
HashMap
中的 Object
在您的情况下是 String
或 Integer
。
因此,如果您从 HashMap
中获取元素 bucket
,您将获取其值。
让我们将其与 for
循环结合起来进一步说明:
List<HashMap<String, Object>> bucketsList = jsonPath.param("j", j).getList("[j].buckets");
for (HashMap<String, Object> singleBucket : bucketsList) {
String firstValue = (String) singleBucket.get("bucket");
Integer secondValue = (Integer) singleBucket.get("original");
}
看错误信息,好像你用的是rest-assured,而JsonPath
class是来自放心库的io.restassured.path.json.JsonPath
。
我相信您知道,但是(可能对其他读者而言)请注意,这与 Jayway's json-path 不同,并且不是该库中的 com.jayway.jsonpath.JsonPath
class。
另请注意,如 manipulating/extracting JSON 的 documentation rest-assured uses the Groovy GPath 语法中所述。
这样,我相信以下内容将提取您需要的内容,即 od_pair 及其相应的可用数字桶:
Map<String, Map<String, Integer>> map = JsonPath.with(jsonString).get("collectEntries{entry -> [entry.od_pair, entry.buckets.collectEntries{bucketEntry -> [bucketEntry.bucket, bucketEntry.available]}]}");
对于映射的每个条目,键是 od_pair,值是另一个映射,其键是桶,值是可用数量。 jsonString
是您在问题中提供的 JSON。
您可以遍历地图以获得您想要的内容:
for(Map.Entry<String, Map<String, Integer>> entry : map.entrySet())
{
String od_pair = entry.getKey();
Map<String, Integer> bucketMap = entry.getValue();
for(Map.Entry<String, Integer> bucketEntry : bucketMap.entrySet())
{
String bucket = bucketEntry.getKey();
int available = bucketEntry.getValue();
}
}
打印地图你会得到:
{7015400:8727100={C00=2, A01=0, B01=480}, 7015400:8814001={C00=2, A01=40, B01=672, B03=632, B05=558}}
使用 Gson 将地图打印为 JSON:
System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(map));
你会得到
{
"7015400:8727100": {
"C00": 2,
"A01": 0,
"B01": 480
},
"7015400:8814001": {
"C00": 2,
"A01": 40,
"B01": 672,
"B03": 632,
"B05": 558
}
}
对于背景,字符串 collectEntries{entry -> [entry.od_pair, entry.buckets.collectEntries{bucketEntry -> [bucketEntry.bucket, bucketEntry.available]}]}
是一个 Groovy 闭包,它使用 Groovy 集合中的方法 API:参考 Collection, List and Map
向@Fenio 大声喊出上述纯 Java 解决方案。