Java 将嵌套的分隔字符串转换为对象

Java 将嵌套的分隔字符串转换为对象,java,json,tree,delimiter-separated-values,Java,Json,Tree,Delimiter Separated Values,我正在尝试转换嵌套的点分隔文件,如下所示: AAA, value1, value11 AAA.BBB, value3, value22 AAA.BBB.CCC, value3, value33 AAA.DDD, values44, value44 对于对象,可以将其描述为JSON: { "name": "AAA", "type": "value1", "property": "value11", "children": [ {

我正在尝试转换嵌套的点分隔文件,如下所示:

AAA, value1, value11
AAA.BBB, value3, value22
AAA.BBB.CCC, value3, value33
AAA.DDD, values44, value44
对于对象,可以将其描述为JSON:

{
    "name": "AAA",
    "type": "value1",
    "property": "value11",
    "children": [
        {
            "name": "BBB",
            "type": "value2",
            "property": "value22",
            "children": [
                {
                    "name": "CCC",
                    "type": "value3",
                    "property": "value33",
                    "children": []
                }
            ]
        },
        {
            "name": "DDD",
            "type": "value4",
            "property": "value44",
            "children": []
        }
    ]
}
请告诉我,如何用Java实现这个案例

我已经尝试过像这样手工制作JSON,但它对我不起作用。我无法正确实现父子结构

静态抽象类节点{
}
静态类中间节点扩展节点{
public Map keyValueMap=新建LinkedHashMap();
@凌驾
公共字符串toString(){
StringBuilder sb=新的StringBuilder();
某人附加(“[{”);
sb.append(keyValueMap.entrySet().stream().map(条目->“\”名称“:\”+条目.getKey()+”,“\”子项“+”:“+条目.getValue())
.collect(收集器。连接(“,”);
某人加上(“}]”;
使某人返回字符串();
}
}
公共无效测试(字符串源){
中间节点根=新中间节点();
字符串[]行=源。拆分(\\n“);
用于(字符串行:行){
列表值=新的LinkedList(Arrays.asList(line.split(“,”));
String[]path=values.get(0).split(“\\”);
中间节点currentNode=根节点;
对于(int i=0;i
可能有更简洁和优雅的方法来实现这一点,但这对于错误、缺少节点和未排序的数据来说应该非常健壮(请参见下面的输入示例;我假设您可以读取该文件,因此我将开始使用字符串列表)

对于初学者来说,最好使用或使用其他库来避免在序列化过程中重新发明轮子和处理各种边缘情况。如果您正在处理看似简单的字符串,那么它可能是可行的,但您自己滚动它应该是最后的手段

至于算法,我的方法是标记每一行并在路径中向后走,为任何缺少的项创建
节点
对象,并将它们保存在由路径名键入的哈希中。每行路径中的最后一项是叶子,将被分配该行的属性,而内部节点使用散列查找并添加来自先前解析的节点的子项。这将构建一个链接的n元树结构

下一步是找到根(我们断言只有一个根)并运行JSON序列化程序,从叶子开始,递归地将序列化对象传递回父对象

请注意,
org.JSON
将对键进行排序,但结果与预期输出一样符合JSON规范,这保证了对象属性没有排序

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONObject;

class Node {
    String name;
    String type;
    String property;
    ArrayList<Node> children;

    public Node(String name, String type, String property, ArrayList<Node> children) {
        this.name = name;
        this.type = type;
        this.property = property;
        this.children = children;
    }

    public JSONObject toJSON() {
        JSONArray serializedChildren = new JSONArray();

        for (Node child : children) {
            serializedChildren.put(child.toJSON());
        }

        return new JSONObject()
            .put("name", name)
            .put("type", type)
            .put("property", property)
            .put("children", serializedChildren);
    }
}

public class Main {
    private static void validate(boolean cond, String msg) {
        if (!cond) throw new IllegalArgumentException(msg);
    }

    private static void parseLine(HashMap<String, Node> nodes, String line) {
        String[] tokens = line.split(", ");
        validate(tokens.length == 3, "There must be 3 tokens per line");
        String[] names = tokens[0].split("\\.");
        validate(names.length != 0, "There must be at least one name in the path");

        for (int i = names.length - 1; i >= 0; i--) {
            String name = String.join(".", Arrays.copyOfRange(names, 0, i + 1));
            Node node = nodes.get(name);

            if (node == null) {
                nodes.put(name, node = new Node(names[i], null, null, new ArrayList<>()));
            }

            if (i < names.length - 1) {
                Node child = nodes.get(name + "." + names[i+1]);
                validate(child != null, "Child lookup must succeed");

                if (!node.children.contains(child)) {
                    node.children.add(child);
                }
            }
            else {
                node.type = tokens[1];
                node.property = tokens[2];
            }
        }
    }

    public static HashSet<Node> parseNodes(List<String> lines) {
        var nodes = new HashMap<String, Node>();
        lines.forEach((line) -> parseLine(nodes, line));

        for (Node node : nodes.values()) {
            String[] tokens = node.name.split("\\.");
            node.name = tokens[tokens.length-1];
        }

        return new HashSet<Node>(nodes.values());
    }

    public static Node findRoot(HashSet<Node> tree) {
        var candidates = new HashSet<Node>(tree);
        tree.forEach((node) -> candidates.removeAll(node.children));
        validate(candidates.size() == 1, "There must be one root");

        for (Node root : candidates) return root;

        return null;
    }

    public static void main(String[] args) {
        var lines = Arrays.asList(
            "AAA.BBB.CCC, value3, value33",
            "AAA.BBB.CCC.EEE.FFF, value5, value55",
            "AAA.BBB, value3, value22",
            "AAA, value1, value11",
            "AAA.DDD, values44, value44"
        );
        Node root = findRoot(parseNodes(lines));
        System.out.println(root.toJSON().toString(2));
    }
}
输出:

{
  "children": [
    {
      "children": [{
        "children": [{
          "children": [{
            "children": [],
            "name": "FFF",
            "property": "value55",
            "type": "value5"
          }],
          "name": "EEE"
        }],
        "name": "CCC",
        "property": "value33",
        "type": "value3"
      }],
      "name": "BBB",
      "property": "value22",
      "type": "value3"
    },
    {
      "children": [],
      "name": "DDD",
      "property": "value44",
      "type": "values44"
    }
  ],
  "name": "AAA",
  "property": "value11",
  "type": "value1"
}

我会使用像
org.json:json
这样的库来实现这一点。这是一个了不起的解决方案!谢谢你的帮助!
{
  "children": [
    {
      "children": [{
        "children": [{
          "children": [{
            "children": [],
            "name": "FFF",
            "property": "value55",
            "type": "value5"
          }],
          "name": "EEE"
        }],
        "name": "CCC",
        "property": "value33",
        "type": "value3"
      }],
      "name": "BBB",
      "property": "value22",
      "type": "value3"
    },
    {
      "children": [],
      "name": "DDD",
      "property": "value44",
      "type": "values44"
    }
  ],
  "name": "AAA",
  "property": "value11",
  "type": "value1"
}