【问题标题】:Convert Map<String, ArrayList<String>> to Nested JSON将 Map<String, ArrayList<String>> 转换为嵌套 JSON
【发布时间】:2020-07-28 09:30:05
【问题描述】:

所以我有一个 Map parentToChild 并且想基本上创建一个“家谱”或嵌套层次结构。下面是地图的一个例子,但每个级别可能有更多的孩子,例如(克莱尔可以把马特和布鲁斯当作孩子):

David -> [Claire]
Claire -> [Matt]
Matt -> [Sean, Terry]

我知道上面例子中树的根应该是大卫,它只有一个根。

示例输出

{
 "David": {
   "Claire": {
      "Matt": {
        "Sean": {},
        "Terry": {}
      }
    }
  }
}

我尝试了几件事,但真的很难过。

编辑:到目前为止尝试的代码

public Set<Tree> transform(Map<String, ArrayList<String>> input) {
        Set<String> roots = new HashSet<String>(input.keySet());

        
        Map<String, Tree> map = new HashMap<String, Tree>();

        for (Map.Entry<String, ArrayList<String>> entry : input.entrySet()) {
            String key = entry.getKey();
            List<String> childKeys = entry.getValue();
            Tree tree = map.get(key);
            if (tree == null) {
                tree = new Tree(key);
                map.put(key, tree);
            }
            for (String childKey : childKeys) {
                roots.remove(childKey);
                Tree child = map.get(childKey);
                if (child == null) {
                    child = new Tree(childKey);
                    map.put(childKey, child);
                }
                tree.addChild(child);
            }
        }
        Set<Tree> res = new HashSet<Tree>(roots.size());
        for (String key : roots) {
            res.add(map.get(key));
        }
        return res;
    }

树类:

public class Tree {
    private String key;
    private Tree child;

    public Tree(String key){
        this.key = key;
    }

    public void addChild(Tree child){
        this.child = child;
    }
}

问题是当我使用此代码时,我得到的输出(调试/打印后的集合中的内容)是

David:
  Claire:
    Matt:
     Terry:

【问题讨论】:

  • "我尝试了一些东西" 你能展示一下你尝试了什么吗?您是在尝试手动生成 JSON,还是您有需要帮助的特定库?
  • 在生成 JSON 时,我们试图以一种通用的方式来实现它,例如获取根并为它下面的每个孩子创建一个 json 对象。所以会遍历每一个。我会尝试重现一些已经完成的事情(删除和 ctrl-z'd 的东西非常沮丧)关于库或从字符串中制作它真的没有偏好。
  • 如果地图上的第一个条目是David -&gt; [Claire, Matt]怎么办?你对Matt 编码两次吗?
  • 对不起,我忘记了,现在将添加它。只有一个孩子可以有一个父母。所以大卫不可能是马特的父母,而克莱尔不可能是马特的父母。
  • 我可以在这里看到两件事:1 将初始结构转换为树 2 序列化。如果结构正确,第二个应该是微不足道的。

标签: java json hashmap


【解决方案1】:

你可以使用Map&lt;String,Object&gt;:

private static final Gson GSON = new GsonBuilder()
        .setPrettyPrinting()
        .create();

public static void main(String[] args) {
    Map<String, List<String>> input = new HashMap<>();
    input.put("David", Arrays.asList("Claire"));
    input.put("Claire", Arrays.asList("Matt"));
    input.put("Matt", Arrays.asList("Sean", "Terry"));
    Map<String,Object> result = new HashMap<>();
    convert(input, "David", result);
    GSON.toJson(result, System.out);
}

private static void convert(Map<String, List<String>> input, String root,
        Map<String,Object> result) {
    if (!result.containsKey(root)) {
        Map<String,Object> rootObj = new HashMap<>();
        result.put(root, rootObj);
        List<String> children = input.get(root);
        if (children != null) {
            for (String child: children) {
                convert(input, child, rootObj);
            }
        }
    }
}

输出:

{
  "David": {
    "Claire": {
      "Matt": {
        "Terry": {},
        "Sean": {}
      }
    }
  }
}

【讨论】:

  • 接受它更多的是基于 Java 的解决方案。但是,Saxon 解决方案也可以使用
【解决方案2】:

在 Java 世界中,您可以访问 Saxon 9.8 或更高版本的 HE,其中 XPath 3.1 或 XQuery 3.1 或 XSLT 3.0 都支持将您的初始地图表示为 XdmMap 并处理它们,例如使用 XQuery:

declare namespace map = "http://www.w3.org/2005/xpath-functions/map";

declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";

declare option output:method 'json';
declare option output:indent 'yes';

declare variable $map as map(xs:string, array(xs:string)) external := map {
    'David' : [ 'Claire' ],
    'Claire' : [ 'Matt' ],
    'Matt' : [ 'Sean', 'Terry' ]
};

declare variable $root as xs:string external := 'David';

declare function local:create-tree($map as map(xs:string, array(xs:string)), $children as xs:string*) as map(*) {
    map:merge($children ! map { . : local:create-tree($map, $map(.)) })
};

local:create-tree($map, $root)

https://xqueryfiddle.liberty-development.net/3Nzd8bV

使用 Saxon 10 HE 运行它的简单 Java 示例(其 API 文档位于 http://saxonica.com/html/documentation/using-xquery/api-query/s9api-query.html),将 Java Map 传递给 XQuery(作为字符串内联插入,但当然可以从文件中加载) 是:

import java.util.HashMap;
import java.util.Map;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XQueryCompiler;
import net.sf.saxon.s9api.XQueryEvaluator;
import net.sf.saxon.s9api.XQueryExecutable;
import net.sf.saxon.s9api.XdmMap;

public class SaxonJavaMapToNestedJSONObject {


    public static void main(String[] args) throws SaxonApiException {
        
        Map<String, String[]> map = new HashMap<>();
        map.put("David", new String[] { "Claire" });
        map.put("Claire", new String[] { "Matt" });
        map.put("Matt", new String[] { "Sean", "Terry" });
        
        Processor processor = new Processor(true);
        
        XQueryCompiler compiler = processor.newXQueryCompiler();
        
        XQueryExecutable executable = compiler.compile("declare namespace map = \"http://www.w3.org/2005/xpath-functions/map\";\n" +
"\n" +
"declare namespace output = \"http://www.w3.org/2010/xslt-xquery-serialization\";\n" +
"\n" +
"declare option output:method 'json';\n" +
"declare option output:indent 'yes';\n" +
"\n" +
"declare variable $map as map(xs:string, array(xs:string)) external;\n" +
"\n" +
"declare variable $root as xs:string external := 'David';\n" +
"\n" +
"declare function local:create-tree($map as map(xs:string, array(xs:string)), $children as xs:string*) as map(*) {\n" +
"    map:merge($children ! map { . : local:create-tree($map, $map(.)) })\n" +
"};\n" +
"\n" +
"local:create-tree($map, $root)");
        
         XQueryEvaluator evaluator = executable.load();
         
         evaluator.setExternalVariable(new QName("map"), XdmMap.makeMap(map));
         
         evaluator.run(processor.newSerializer(System.out));
         
    }
    
}

当然,您也可以从 Java 中设置 root 变量:evaluator.setExternalVariable(new QName("root"), new XdmAtomicValue("David"));

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2019-05-31
  • 1970-01-01
  • 2016-07-29
  • 2013-05-24
  • 2014-01-29
  • 1970-01-01
  • 1970-01-01
  • 2016-07-21
相关资源
最近更新 更多