java—如果数组中的对象包含具有特定值的键,如何在json中删除该对象?

efzxgjgh  于 2021-06-30  发布在  Java
关注(0)|答案(1)|浏览(315)

我有一个嵌套的json,我需要用一个过滤器删除数组中的一些对象,这是一个动态的方式,这个json结构并不总是相同的,例如:

{
    "A": "HI",
    "B": 1, 
    "C": [
        {
            "TIME": "TODAY",
            "LOCATION": "USA",
            "BALANCE": 100,
            "STATE": "TX",
            "NAME": "JHON"
        },
        {
            "TIME": "YESTERDAY",
            "LOCATION": "USA",
            "BALANCE": 100,
            "STATE": "TX",
            "NAME": "MICHAEL"
        },
        {
            "TIME": "YESTERDAY",
            "LOCATION": "USA",
            "BALANCE": 100,
            "STATE": "TX",
            "NAME": "REBECCA"
        }
    ]
}

现在,从这种嵌套的json中,我想删除包含键“name”和值“michael”的对象,结果是:

{
    "A": "HI",
    "B": 1, 
    "C": [
        {
            "TIME": "TODAY",
            "LOCATION": "USA",
            "BALANCE": 100,
            "STATE": "TX",
            "NAME": "JHON"
        },
        {
            "TIME": "YESTERDAY",
            "LOCATION": "USA",
            "BALANCE": 100,
            "STATE": "TX",
            "NAME": "REBECCA"
        }
    ]
}

每次json都会发生变化,这取决于api的响应,只是我需要匹配key-value来删除我需要过滤的对象,而不需要修改json结构,在这种情况下,我需要接收key=“name”和value=“michael”来过滤这个对象。
在这种情况下,“c”是一个变量键,我可以在同一个json中有更多需要过滤的带有数组的键,我需要一种动态的方法来过滤基于键值的对象数组
你能帮我找到一个实现这个功能的方法吗?

wqnecbli

wqnecbli1#

这是一个流解决方案,可以处理巨大的响应,而不会对您的系统造成任何重大影响。它也不需要任何使用内置json节点表示的类Map(因此在类型绑定上节省时间和内存)。

public static void filterAbcBySpecializedStreaming(final JsonReader input, final JsonWriter output)
        throws IOException {
    input.beginObject();
    output.beginObject();
    // iterating over each entry of the outer object
    while ( input.hasNext() ) {
        final String name = input.nextName();
        output.name(name);
        switch ( name ) {
        // assuming "A" is known to be a string always
        case "A":
            output.value(input.nextString());
            break;
        // assuming "B" is known to be a number always
        case "B":
            // note: JsonReader does not allow to read a number of an arbitrary length as an instance of `java.lang.Number`
            output.value(new LazilyParsedNumber(input.nextString()));
            break;
        // assuming "C" is known to be an array of objects always
        case "C":
            input.beginArray();
            output.beginArray();
            // iterating over each element of the array
            while ( input.hasNext() ) {
                // assuming array elements are not very big and it trusts their size
                final JsonObject jsonObject = Streams.parse(input)
                        .getAsJsonObject();
                // if the current element JSON object has a property named "NAME" and its value is set to "MICHAEL", the skip it
                // of course, this can also be externalized using the Strategy design pattern (e.g. using java.lang.function.Predicate)
                // but this entire method is not that generic so probably it's fine
                if ( jsonObject.get("NAME").getAsString().equals("MICHAEL") ) {
                    continue;
                }
                Streams.write(jsonObject, output);
            }
            input.endArray();
            output.endArray();
            break;
        default:
            throw new IllegalStateException("Unknown: " + name);
        }
    }
    input.endObject();
    output.endObject();
}

测试:

final JsonElement expected = Streams.parse(expectedJsonReader);
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
final JsonWriter output = new JsonWriter(new OutputStreamWriter(buffer));
Filter.filterAbcBySpecializedStreaming(input, output);
output.flush();
final JsonElement actual = JsonParser.parseReader(new InputStreamReader(new ByteArrayInputStream(buffer.toByteArray())));
Assertions.assertEquals(expected, actual);

当然,这不是那么容易,但它可能会导致最好的表现。使它通用和“动态”是一个选择,它可以根据您的需要。如果您发现它太复杂,那么输入的json文档就不会很大(因此 OutOfMemoryError s) ,也可以将其作为树进行筛选,但同样不需要任何类型绑定:

public static void filterAbcBySpecializedTree(final JsonElement input, final JsonElement output) {
    final JsonObject inputJsonObject = input.getAsJsonObject();
    final JsonObject outputJsonObject = output.getAsJsonObject();
    for ( final Map.Entry<String, JsonElement> e : inputJsonObject.entrySet() ) {
        final String name = e.getKey();
        final JsonElement value = e.getValue();
        switch ( name ) {
        case "A":
        case "B":
            outputJsonObject.add(name, value.deepCopy());
            break;
        case "C":
            final JsonArray valueJsonArray = value.getAsJsonArray()
                    .deepCopy();
            for ( final Iterator<JsonElement> it = valueJsonArray.iterator(); it.hasNext(); ) {
                final JsonObject elementJsonObject = it.next().getAsJsonObject();
                if ( elementJsonObject.get("NAME").getAsString().equals("MICHAEL") ) {
                    it.remove();
                }
            }
            outputJsonObject.add(name, valueJsonArray);
            break;
        default:
            throw new IllegalStateException("Unknown: " + name);
        }
    }
}

测试:

final JsonElement input = Streams.parse(inputJsonReader);
final JsonElement expected = Streams.parse(expectedJsonReader);
final JsonElement actual = new JsonObject();
Filter.filterAbcBySpecializedTree(input, actual);
Assertions.assertEquals(expected, actual);

相关问题