如何通过Gson获取过滤的JSON节点?

时间:2017-04-04 07:03:54

标签: json gson

我正在使用Gson来解析和编写JSON数据。

namespace inet {

    Define_Module(PC);

    void PC::initialize() {
      TCPSocket mysocket;
      // ...
    }
}

如何根据某些属性值获取JSON节点?例如,我想获得一个值为[{ "Source":"IN", "Type":"PRD", "Name":"ABC" "IsActive":true }, { "Source":"IN", "Type":"COB", "Name":"XYZ" "IsActive":true }, { "Source":"PRo", "Type":"RPT", "Name":"TEST" "IsActive":true }] = SourcePRo = TypeRPT = Name的节点。

我怎么能用Gson做到这一点?

1 个答案:

答案 0 :(得分:3)

正如我上面所说,Gson不是一个查询库。但是你可以在Gson中使用至少四种策略:

  • 使用内存策略
    • 使用JSON树模型
    • 使用动态映射
    • 使用静态映射
  • 使用流媒体策略

上述每一项都有其优点和缺点。对特定节点应用一些修改是一个简单的filter-and-then-forEach问题,并且可以使用命令式for / if或使用Java 8 Stream API轻松解决。

JSON树模型

JSON树模型用于在内存中构建特定JSON文档的JSON表示。具有类似DOM的结构,您可以轻松遍历和修改任何树叶。但是,它需要大量的内存。

try ( final Reader reader = getPackageResourceReader(Q43200432.class, "q43200432.json") ) {
    final JsonArray rows = jsonParser.parse(reader).getAsJsonArray();
    StreamSupport.stream(rows.spliterator(), false)
            .map(JsonElement::getAsJsonObject)
            .filter(jsonObject -> jsonObject.get("Source").getAsString().equals("PRo")
                    && jsonObject.get("Type").getAsString().equals("RPT")
                    && jsonObject.get("Name").getAsString().equals("TEST")
            )
            .forEach(jsonObject -> jsonObject.add("IsActive", new JsonPrimitive(false)));
    System.out.println(rows);
}

JSON映射到Map< String,Object>

与上面类似,但行结构甚至不与Gson JSON树模型API绑定,因此值可以是字面上的任何类型。

private static final Gson gson = new Gson();

private static final Type rowListType = new TypeToken<List<Map<String, Object>>>() {
}.getType();

...

try ( final Reader reader = getPackageResourceReader(Q43200432.class, "q43200432.json") ) {
    final List<Map<String, Object>> rows = gson.fromJson(reader, rowListType);
    rows.stream()
            .filter(r -> r.get("Source").equals("PRo")
                    && r.get("Type").equals("RPT")
                    && r.get("Name").equals("TEST"))
            .forEach(r -> r.put("IsActive", false));
    System.out.println(gson.toJson(rows, rowListType));
}

JSON映射到自定义映射(普通旧Java对象)

final class Row {

    @SerializedName("Source")
    String source;

    @SerializedName("Type")
    String type;

    @SerializedName("Name")
    String name;

    @SerializedName("IsActive")
    boolean isActive;

}
private static final Gson gson = new Gson();

private static final Type rowListType = new TypeToken<List<Row>>() {
}.getType();

...

try ( final Reader reader = getPackageResourceReader(Q43200432.class, "q43200432.json") ) {
    final List<Row> rows = gson.fromJson(reader, rowListType);
    rows.stream()
            .filter(r -> "PRo".equals(r.source) && "RPT".equals(r.type) && "TEST".equals(r.name))
            .forEach(r -> r.isActive = false);
    System.out.println(gson.toJson(rows, rowListType));
}

Streaming允许通过令牌读取JSON令牌并进行某种分析。由于流式传输不需要将整个文档存储在内存中,因此它甚至可以处理无限的流,但是它可能看起来有点难以使用。

private static final Gson gson = new Gson();

...

final TypeAdapter<JsonObject> jsonObjectTypeAdapter = gson.getAdapter(JsonObject.class);
final Writer writer = new StringWriter();
try ( final JsonReader jsonReader = new JsonReader(getPackageResourceReader(Q43200432.class, "q43200432.json"));
      final JsonWriter jsonWriter = new JsonWriter(writer) ) {
    jsonReader.beginArray();
    jsonWriter.beginArray();
    while ( jsonReader.hasNext() ) {
        final JsonObject jsonObject = jsonObjectTypeAdapter.read(jsonReader);
        if ( jsonObject.get("Source").getAsString().equals("PRo")
                && jsonObject.get("Type").getAsString().equals("RPT")
                && jsonObject.get("Name").getAsString().equals("TEST") ) {
            jsonObject.add("IsActive", new JsonPrimitive(false));
        }
        jsonObjectTypeAdapter.write(jsonWriter, jsonObject);
    }
    jsonReader.endArray();
    jsonWriter.endArray();
}
System.out.println(writer);

上述所有四种策略都会产生以下输出:

  

[{ “源”: “IN”, “类型”: “PRD”, “名称”: “ABC”, “IsActive”:真},{ “源”: “IN”, “类型”:” COB”, “姓名”: “XYZ”, “IsActive”:真正},{ “源”: “亲”, “类型”: “RPT”, “姓名”: “TEST”, “IsActive”:假}]

请注意,位于$[2].IsActive的最后一个元素设置为false