【问题标题】:Collect all elements in a JSON file into a single list将 JSON 文件中的所有元素收集到一个列表中
【发布时间】:2021-04-17 13:50:14
【问题描述】:

我正在使用 Gson 2.8.1+(如果需要,我可以升级)。

如果我有 JsonObject:

"config" : {
        "option_one" : {
            "option_two" : "result_one"
        }
    }
}

...如何有效地将其转换为表单:

"config.option_one.option_two" : "result_one"

【问题讨论】:

    标签: java json gson


    【解决方案1】:

    简单示例:

    public static void main(String[] args) {
        String str = """
        {
            "config" : {
                "option_one" : {
                    "option_two" : "result_one"
                }
            }
        }""";
        var obj = JsonParser.parseString(str).getAsJsonObject();
        System.out.println(flatten(obj)); // {"config.option_one.option_two":"result_one"}
    }
    
    public static JsonObject flatten(JsonObject toFlatten) {
        var flattened = new JsonObject();
        flatten0("", toFlatten, flattened);
        return flattened;
    }
    
    private static void flatten0(String prefix, JsonObject toFlatten, JsonObject toMutate) {
        for (var entry : toFlatten.entrySet()) {
            var keyWithPrefix = prefix + entry.getKey();
            if (entry.getValue() instanceof JsonObject child) {
                flatten0(keyWithPrefix + ".", child, toMutate);
            } else {
                toMutate.add(keyWithPrefix, entry.getValue());
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      算法

      您能想到的最简单的算法是递归折叠。您首先递归地潜入结构的底部,然后询问地图中是否只有一个元素(您必须使用一些框架解析 json 以获得 Map 结构)。如果有,则将父字段的字符串与属性连接起来,并将父字段的值设置为该属性的值。然后你向上移动并重复这个过程,直到你在根。当然,如果 map 有多个字段,你会转到 parent 并尝试 egan。

      【讨论】:

        【解决方案3】:

        Gson 没有类似的东西,但它提供了足够的能力来构建它:你可以遍历 JSON 流 (JsonReader) 和树 (JsonElement,但不能包装到 JsonReader) 基于堆栈并相应地基于堆栈/递归(流可能会节省很多)。

        我会创建一个通用的树遍历方法以适应进一步的目的。

        public static void walk(final JsonElement jsonElement, final BiConsumer<? super Collection<?>, ? super JsonElement> consumer) {
            final Deque<Object> parents = new ArrayDeque<>();
            parents.push("$");
            walk(jsonElement, consumer, parents);
        }
        
        private static void walk(final JsonElement jsonElement, final BiConsumer<? super Collection<?>, ? super JsonElement> consumer, final Deque<Object> path) {
            if ( jsonElement.isJsonNull() ) {
                consumer.accept(path, jsonElement);
            } else if ( jsonElement.isJsonPrimitive() ) {
                consumer.accept(path, jsonElement);
            } else if ( jsonElement.isJsonObject() ) {
                for ( final Map.Entry<String, JsonElement> e : jsonElement.getAsJsonObject().entrySet() ) {
                    path.addLast(e.getKey());
                    walk(e.getValue(), consumer, path);
                    path.removeLast();
                }
            } else if ( jsonElement.isJsonArray() ) {
                int i = 0;
                for ( final JsonElement e : jsonElement.getAsJsonArray() ) {
                    path.addLast(i++);
                    walk(e, consumer, path);
                    path.removeLast();
                }
            } else {
                throw new AssertionError(jsonElement);
            }
        }
        

        请注意,上面的方法也支持数组。 walk 方法是推送语义驱动的:它使用回调来提供步行进度。通过返回迭代器或流使其变得懒惰可能会更便宜并应用拉语义。此外,CharSequence 视图元素可能会节省创建许多字符串的时间。

        public static String toJsonPath(final Iterable<?> path) {
            final StringBuilder stringBuilder = new StringBuilder();
            final Iterator<?> iterator = path.iterator();
            if ( iterator.hasNext() ) {
                final Object next = iterator.next();
                stringBuilder.append(next);
            }
            while ( iterator.hasNext() ) {
                final Object next = iterator.next();
                if ( next instanceof Number ) {
                    stringBuilder.append('[').append(next).append(']');
                } else if ( next instanceof CharSequence ) {
                    stringBuilder.append('.').append(next);
                } else {
                    throw new UnsupportedOperationException("Unsupported: " + next);
                }
            }
            return stringBuilder.toString();
        }
        

        测试:

        final JsonElement jsonElement = Streams.parse(jsonReader);
        final Collection<String> paths = new ArrayList<>();
        JsonPaths.walk(jsonElement, (path, element) -> paths.add(JsonPaths.toJsonPath(path)));
        for ( final String path : paths ) {
            System.out.println(path);
        }
        Assertions.assertIterableEquals(
                ImmutableList.of(
                        "$.nothing",
                        "$.number",
                        "$.object.subobject.number",
                        "$.array[0].string",
                        "$.array[1].string",
                        "$.array[2][0][0][0]"
                ),
                paths
        );
        

        【讨论】:

          猜你喜欢
          • 2021-11-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-02
          相关资源
          最近更新 更多