如何处理含@符号的JSON-LD文档的JsonPath筛选问题
解决JsonPath筛选含@符号的JSON-LD字段问题
我明白你遇到的痛点了——JSON-LD里的@type、@id这类带@的字段,在JsonPath里直接用会踩坑,因为@在JsonPath里是特殊运算符(用来指代当前节点),不是字段名的一部分。下面给你一步步拆解解决方案:
核心问题:JsonPath对特殊字符键名的处理
当JSON键名包含@、$这类特殊字符时,不能直接写orderDelivery[@type],必须用单引号或双引号把键名包裹起来,告诉JsonPath这是一个字面量的键名,而不是语法符号。正确的写法是orderDelivery['@type'](Java里用单引号更方便,不用转义双引号)。
解决方案1:筛选orderDelivery[@type]匹配指定值的订单
先修正你的代码两个关键问题:
- 修复JsonPath的字段引用语法
- 解决InputStream只能读取一次的问题(原代码里第二次读流会为空)
修正后的完整代码:
JsonArray getOrdersByDeliveryType(String orderDeliveryType) throws NoOrdersForDriverFoundException { // 先把流转换成字符串缓存,避免重复读取流导致的空内容问题 String jsonContent; try (InputStream ordersAsStream = /* 你的文档读取逻辑,比如从文件/网络获取 */) { jsonContent = new String(ordersAsStream.readAllBytes(), StandardCharsets.UTF_8); } catch (IOException e) { throw new RuntimeException("Failed to load orders document", e); } // 用单引号包裹带@的字段名,修正JsonPath筛选规则 Filter deliveryTypeFilter = Filter.filter( Criteria.where("orderDelivery['@type']").eq(orderDeliveryType) ); // 执行筛选:$[*]表示所有根节点下的订单,[?]应用筛选器 List<Map<String, Object>> filteredOrders = JsonPath.parse(jsonContent) .read("$[*][?]", deliveryTypeFilter); if(filteredOrders == null || filteredOrders.isEmpty()) { throw new NoOrdersForDriverFoundException(); } // 将筛选后的Map列表转换为JsonArray JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); for (Map<String, Object> order : filteredOrders) { arrayBuilder.add(Json.createObjectBuilder(order)); } return arrayBuilder.build(); }
解决方案2:筛选orderDelivery.provider.employee[@id]匹配指定ID的订单
同样的逻辑,只需要修改筛选器的路径即可:
JsonArray getOrdersByEmployeeId(String targetEmployeeId) throws NoOrdersForDriverFoundException { String jsonContent; try (InputStream ordersAsStream = /* 你的文档读取逻辑 */) { jsonContent = new String(ordersAsStream.readAllBytes(), StandardCharsets.UTF_8); } catch (IOException e) { throw new RuntimeException("Failed to load orders document", e); } // 嵌套字段的筛选:同样用单引号包裹@id Filter employeeIdFilter = Filter.filter( Criteria.where("orderDelivery.provider.employee['@id']").eq(targetEmployeeId) ); List<Map<String, Object>> filteredOrders = JsonPath.parse(jsonContent) .read("$[*][?]", employeeIdFilter); if(filteredOrders.isEmpty()) { throw new NoOrdersForDriverFoundException(); } JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); for (Map<String, Object> order : filteredOrders) { arrayBuilder.add(Json.createObjectBuilder(order)); } return arrayBuilder.build(); }
关键总结
- 特殊键名处理:所有带@、$等特殊字符的JSON键,在JsonPath中必须用
['键名']或["键名"]包裹 - 流的复用问题:InputStream是一次性读取的,必须先转换成字符串或字节数组缓存,避免二次读取为空
- 结果转换:JsonPath返回的
List<Map>需要手动转换成JsonArray,不能直接复用原流读取
内容的提问来源于stack exchange,提问作者viggis75
相关产品推荐
相关产品推荐

