在不反序列化的情况下从 JSON 字符串中的任何位置删除键
Remove keys from anywhere in a JSON string without deserialization
如果不反序列化和重新序列化以下深层嵌套的 JSON 字符串(如果可能的话),如何从任何嵌套级别删除名称为 "REMOVEME" 的任何键?
尝试过:
不情愿地尝试反序列化到JsonObject
/LinkedHashMap
以遍历带有node.remove(e.getKey())
的结构在违规键上,但Gson抛出并发修改异常,Jackson要求完全反序列化。
之前:
{
"a": {
"REMOVEME" : "unwanted",
"b": {
"REMOVEME" : "unwanted",
"c": {
"d": {
"REMOVEME" : "unwanted",
"something": "default",
"e": {
"f": {
"REMOVEME" : "unwanted",
"g": {
"REMOVEME" : "unwanted",
"h": {
... ,
之后:
{
"a": {
"b": {
"c": {
"d": {
"something": "default",
"e": {
"f": {
"g": {
"h": {
... ,
如果对象的确切值和名称已知,您可以对其进行正则表达式替换,例如:
jsonString.replaceAll("\"REMOVEME\" ?: ?\"unwanted\"[,}]","")
否则如果只知道key,还是可以用稍微复杂一点的表达式来匹配:
\"REMOVEME\" ?: ?.+[,}]
或者,如果只知道该值,则向后推。
\".+\" ?: ?\"unwanted\"[,}]
如果它们都是动态的,但您仍然有它们的列表,您应该能够遍历它们,动态地将每个 key/value 更改为匹配的。
我不确定您尝试从节点中删除 属性 的方式,但是可以删除 属性 我是使用 jackson
做到的
String json = "{\n" +
" \"a\": {\n" +
" \"REMOVEME\" : \"unwanted\",\n" +
" \"b\": {\n" +
" \"REMOVEME\" : \"unwanted\"\n" +
" }\n" +
" }\n" +
"}";
JsonNode node = objectMapper.readTree(json);
ObjectNode node1 = (ObjectNode) node.get("a");
node1.remove("REMOVEME");
System.out.println(node1); // {"b":{"REMOVEME":"unwanted"}}
System.out.println(node); // {"a":{"b":{"REMOVEME":"unwanted"}}}
解决这个问题的一种方法是使用 Gson 进行流式令牌解析。此方法可以轻松处理非常大的 JSON 字符串。
前后示例:
{"a":{"removeme":"unwanted","b":{"c":{"removeme":{"x":1},"d":{"e":123}}}}}
{"a":{"b":{"c":{"d":{"e":123}}}}}
基本测试工具:
String rawJson = "{\"a\":{\"removeme\":\"unwanted\",\"b\":{\"c\":{\"removeme\":{\"x\":1},\"d\":{\"e\":123}}}}}";
final Gson gson = new GsonBuilder().create();
JsonReader reader = gson.newJsonReader( new StringReader( rawJson ) );
StringWriter outWriter = new StringWriter();
JsonWriter writer = gson.newJsonWriter( outWriter );
JsonStreamFilter.streamFilter( reader, writer, Arrays.asList( "removeme" ) );
System.out.println( rawJson );
System.out.println( outWriter.toString() );
分词和过滤魔法:
public class JsonStreamFilter
{
/**
* Filter out all properties with names included in the `propertiesToRemove` list.
*
* @param reader JsonReader to read in the JSON token
* @param writer JsonWriter to accept modified JSON tokens
* @param propertiesToRemove List of property names to remove
* @throws IOException
* @see Gson docs at https://sites.google.com/site/gson/streaming
*/
public static void streamFilter(
final JsonReader reader,
final JsonWriter writer,
final List<String> propertiesToRemove
) throws IOException
{
while ( true )
{
JsonToken token = reader.peek();
switch ( token )
{
case BEGIN_ARRAY:
reader.beginArray();
writer.beginArray();
break;
case END_ARRAY:
reader.endArray();
writer.endArray();
break;
case BEGIN_OBJECT:
reader.beginObject();
writer.beginObject();
break;
case END_OBJECT:
reader.endObject();
writer.endObject();
break;
case NAME:
String name = reader.nextName();
// Skip all nested structures stemming from this property
if ( propertiesToRemove.contains( name ) )
{
reader.skipValue();
break;
}
writer.name( name );
break;
case STRING:
String s = reader.nextString();
writer.value( s );
break;
case NUMBER:
String n = reader.nextString();
writer.value( new BigDecimal( n ) );
break;
case BOOLEAN:
boolean b = reader.nextBoolean();
writer.value( b );
break;
case NULL:
reader.nextNull();
writer.nullValue();
break;
case END_DOCUMENT:
return;
}
}
}
}
如果不反序列化和重新序列化以下深层嵌套的 JSON 字符串(如果可能的话),如何从任何嵌套级别删除名称为 "REMOVEME" 的任何键?
尝试过:
不情愿地尝试反序列化到JsonObject
/LinkedHashMap
以遍历带有node.remove(e.getKey())
的结构在违规键上,但Gson抛出并发修改异常,Jackson要求完全反序列化。
之前:
{
"a": {
"REMOVEME" : "unwanted",
"b": {
"REMOVEME" : "unwanted",
"c": {
"d": {
"REMOVEME" : "unwanted",
"something": "default",
"e": {
"f": {
"REMOVEME" : "unwanted",
"g": {
"REMOVEME" : "unwanted",
"h": {
... ,
之后:
{
"a": {
"b": {
"c": {
"d": {
"something": "default",
"e": {
"f": {
"g": {
"h": {
... ,
如果对象的确切值和名称已知,您可以对其进行正则表达式替换,例如:
jsonString.replaceAll("\"REMOVEME\" ?: ?\"unwanted\"[,}]","")
否则如果只知道key,还是可以用稍微复杂一点的表达式来匹配:
\"REMOVEME\" ?: ?.+[,}]
或者,如果只知道该值,则向后推。
\".+\" ?: ?\"unwanted\"[,}]
如果它们都是动态的,但您仍然有它们的列表,您应该能够遍历它们,动态地将每个 key/value 更改为匹配的。
我不确定您尝试从节点中删除 属性 的方式,但是可以删除 属性 我是使用 jackson
做到的String json = "{\n" +
" \"a\": {\n" +
" \"REMOVEME\" : \"unwanted\",\n" +
" \"b\": {\n" +
" \"REMOVEME\" : \"unwanted\"\n" +
" }\n" +
" }\n" +
"}";
JsonNode node = objectMapper.readTree(json);
ObjectNode node1 = (ObjectNode) node.get("a");
node1.remove("REMOVEME");
System.out.println(node1); // {"b":{"REMOVEME":"unwanted"}}
System.out.println(node); // {"a":{"b":{"REMOVEME":"unwanted"}}}
解决这个问题的一种方法是使用 Gson 进行流式令牌解析。此方法可以轻松处理非常大的 JSON 字符串。
前后示例:
{"a":{"removeme":"unwanted","b":{"c":{"removeme":{"x":1},"d":{"e":123}}}}}
{"a":{"b":{"c":{"d":{"e":123}}}}}
基本测试工具:
String rawJson = "{\"a\":{\"removeme\":\"unwanted\",\"b\":{\"c\":{\"removeme\":{\"x\":1},\"d\":{\"e\":123}}}}}";
final Gson gson = new GsonBuilder().create();
JsonReader reader = gson.newJsonReader( new StringReader( rawJson ) );
StringWriter outWriter = new StringWriter();
JsonWriter writer = gson.newJsonWriter( outWriter );
JsonStreamFilter.streamFilter( reader, writer, Arrays.asList( "removeme" ) );
System.out.println( rawJson );
System.out.println( outWriter.toString() );
分词和过滤魔法:
public class JsonStreamFilter
{
/**
* Filter out all properties with names included in the `propertiesToRemove` list.
*
* @param reader JsonReader to read in the JSON token
* @param writer JsonWriter to accept modified JSON tokens
* @param propertiesToRemove List of property names to remove
* @throws IOException
* @see Gson docs at https://sites.google.com/site/gson/streaming
*/
public static void streamFilter(
final JsonReader reader,
final JsonWriter writer,
final List<String> propertiesToRemove
) throws IOException
{
while ( true )
{
JsonToken token = reader.peek();
switch ( token )
{
case BEGIN_ARRAY:
reader.beginArray();
writer.beginArray();
break;
case END_ARRAY:
reader.endArray();
writer.endArray();
break;
case BEGIN_OBJECT:
reader.beginObject();
writer.beginObject();
break;
case END_OBJECT:
reader.endObject();
writer.endObject();
break;
case NAME:
String name = reader.nextName();
// Skip all nested structures stemming from this property
if ( propertiesToRemove.contains( name ) )
{
reader.skipValue();
break;
}
writer.name( name );
break;
case STRING:
String s = reader.nextString();
writer.value( s );
break;
case NUMBER:
String n = reader.nextString();
writer.value( new BigDecimal( n ) );
break;
case BOOLEAN:
boolean b = reader.nextBoolean();
writer.value( b );
break;
case NULL:
reader.nextNull();
writer.nullValue();
break;
case END_DOCUMENT:
return;
}
}
}
}