在Java中将JSON转换为外观不同的CSV

在Java中将JSON转换为外观不同的CSV,java,json,csv,Java,Json,Csv,我需要写一个代码,将JSON文件转换为CSV。问题出在CSV文件的格式上 输入json: { "strings":{ "1level1":{ "1level2":{ "1label1":"1value1", "1label2":"1value2" }

我需要写一个代码,将JSON文件转换为CSV。问题出在CSV文件的格式上

输入json:

{
   "strings":{
      "1level1":{
         "1level2":{
            "1label1":"1value1",
            "1label2":"1value2"
         }
      },
      "2level1":{
         "2level2":{
            "2level3":{
               "2label1":"2value1"
            },
            "2label2":"2value2"
         }
      }
   }
}
这是此json的预期csv文件:

Keys,Default
1level1.1level2.1label1,1value1
1level1.1level2.1label2,1value2
2level1.2level2.2level3.2label1,2value1
2level1.2level2.2label2,2value2
我试图使用递归遍历JSON文件,但这对我来说不起作用,因为每次迭代都要重写JSON对象,代码只在第一个值之前有效。对于如何做到这一点,有什么建议吗

注意:您尝试过使用不同的JSON库,因此目前可以使用其中任何一个

更新#1: 我试图使用非工作代码示例遍历JSON树:

public static void jsonToCsv() throws JSONException {
    InputStream is = MainClass.class.getResourceAsStream("/fromJson.json");
    JSONTokener jsonTokener = new JSONTokener(is);

    JSONObject jsonObject = new JSONObject(jsonTokener);
    stepInto(jsonObject);
}

private static void stepInto(JSONObject jsonObject) {
    JSONObject object = jsonObject;
    try {
        Set < String > keySet = object.keySet();
        for (String key: keySet) {
            object = object.getJSONObject(key);
            stepInto(object);
        }
    } catch (JSONException e) {
        Set < String > keySet = object.keySet();
        for (String key: keySet) {
            System.out.println(object.get(key));
        }

        e.printStackTrace();
    }

}
publicstaticvoid jsonToCsv()抛出JSONException{
InputStream=MainClass.class.getResourceAsStream(“/fromJson.json”);
JSONTokener JSONTokener=新的JSONTokener(is);
JSONObject JSONObject=新的JSONObject(jsonTokener);
stepino(jsonObject);
}
私有静态void单步插入(JSONObject JSONObject){
JSONObject对象=JSONObject;
试一试{
SetkeySet=object.keySet();
用于(字符串键:键集){
object=object.getJSONObject(键);
进入(客体);
}
}捕获(JSONException e){
SetkeySet=object.keySet();
用于(字符串键:键集){
System.out.println(object.get(key));
}
e、 printStackTrace();
}
}
更新#2: 另一个问题是,我永远不会知道JSON对象的名称和子对象的数量(同时更新JSON和CSV示例以使图像更清晰)。众所周知,它总是以字符串对象开头

使用的图书馆:

<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20180813</version>
</dependency>

org.json
json
20180813

我想你只是忘记了记录你的结果,否则看起来不错

假设您的结果是一个简单的字符串。然后,在遍历json对象时必须连接所有键,直到达到一个基本值(如数字或字符串)

(这是我自己写的,请原谅我的语法错误)

如你所见,我没有改变你原来的方法。唯一的区别是,现在我们跟踪每个递归调用的键(
“level1.level2…”

编辑

我添加了一个
+“\n”
更重要的是,我不是每次都返回,而是将每次调用的结果添加到字符串中,因此我们继续循环键并连接所有结果。该方法的每次调用只会在所有键循环一次后返回。(很抱歉错过了)

在调用方法中,您可以打印出结果,类似于:

JSONObject jsonObject = new JSONObject(jsonTokener);
String result = stepInto(jsonObject);
System.out.println(result);

因此,我自己找到了一个解决方案:

public static void jsonToCsv() throws JSONException, IOException {
    InputStream is = MainClass.class.getResourceAsStream("/fromJson.json");
    JSONTokener jsonTokener = new JSONTokener(is);

    JSONObject jsonObject = new JSONObject(jsonTokener).getJSONObject("strings");
    builder = new StringBuilder();

    while (!jsonObject.isEmpty()) {
        stepInto(jsonObject);
    }

    String[] lines = builder.toString().split("\n"); // builder lines are in reverse order from expected so this array is used to reverse them

    FileWriter csvWriter = new FileWriter("src/main/resources/toCsv.csv");
    csvWriter.append("Keys,Default (en_US)\n");

    for (int i = lines.length - 1; i >= 0; i--) {
        csvWriter.append(lines[i]).append("\n");
    }

    csvWriter.flush();
    csvWriter.close();
}


private static void stepInto(JSONObject jsonObject) {
    for (String key: jsonObject.keySet()) {
        Object object = jsonObject.get(key);
        if (object instanceof JSONObject) {
            builder.append(key).append(".");
            stepInto(jsonObject.getJSONObject(key));
        } else {
            builder.append(key).append(",").append(object).append("\n");
            jsonObject.remove(key);
            break;
        }

        if (jsonObject.getJSONObject(key).isEmpty()) {
            jsonObject.remove(key);
        }
        break;
    }
}

你为什么不发布你的递归解决方案,然后我们就可以帮你找到问题了?我很确定你不需要任何花哨的json库。任何有效的JSON都只是一个带有键值对的
map
。您应该能够逐级遍历该地图并构建CSV线。@Gamedroid我添加了我尝试使用的代码(我知道这不好),并添加了一些注释以使图像更清晰。请再看一次,问题是,在这种情况下,它将只通过第一个树(“1Level 1.1Level 2…”),而忽略另一个树(“2Level 1.2Level 2…”),不是吗?请查看我的编辑。我忘记了该方法将在第一个值处终止。现在它继续循环并应该遍历此代码的整个对象输出:
strings.2level1.2level2.2label2.2value2
2level3.2label1.2value1
2level3.{“2label1”:“2value1”}
2level2.{“2label2”:“2value2”,“2level3”:{“2label1”:“2value1”}
2level1.{“2label2”:“2label2”:“2label2”,“2level3”:{“2label1”:“2value1”}}
1level1.1level2.1label2.1value2
1label1.1value1
1level2.{“1label2”:“1value2”、“1label1”:“1value1”}
1level1.{“1level2”:{“1label2”:“1label2”:“1value1”}
字符串。{“2level1”:“2label2”:“2label2”:“1value1”{1level2:{“1label2”:“1value2”,“1label1”:“1value1”}}}}
在main方法中创建StringBuilder并将其作为参数传递给stepInto有助于避免此类输出,但仍然没有找到让代码通过完整树的方法(每一行都以
字符串开头。
以后可以很容易地替换。目前,我使用StringBuilder的建议获得了这样的输出:
字符串。2level1.2level2.2label2,2value2
2level3.2label1,2value1
1level1.1label2.1value2
1label1,1value1
已经找到了解决方案和位置。)ted它。你可以检查一下你是否感兴趣。谢谢你!很好的解决方案!如果可以的话:你正在
静态
环境中运行你的方法,这很好。但是由于你的
StringBuilder
是全局和静态的,你的程序只有一个生成器的实例-所以当你多次执行函数时最近,它将尝试(可能)用一个StringBuilder将不同的JSON读入不同的CSV。想法:将本地StringBuilder传递给您的
stepInto
方法。您的
jsonToCsv
方法保存并创建SB实例,并将其传递给
stepInto
(您只需将其与递归调用一起传递)。你觉得怎么样?@GameDroids这段代码只是在单独的项目中编写的,以便于开发。当我将它转移到主项目时,我会按照你说的那样做:)但是谢谢你的建议!
public static void jsonToCsv() throws JSONException, IOException {
    InputStream is = MainClass.class.getResourceAsStream("/fromJson.json");
    JSONTokener jsonTokener = new JSONTokener(is);

    JSONObject jsonObject = new JSONObject(jsonTokener).getJSONObject("strings");
    builder = new StringBuilder();

    while (!jsonObject.isEmpty()) {
        stepInto(jsonObject);
    }

    String[] lines = builder.toString().split("\n"); // builder lines are in reverse order from expected so this array is used to reverse them

    FileWriter csvWriter = new FileWriter("src/main/resources/toCsv.csv");
    csvWriter.append("Keys,Default (en_US)\n");

    for (int i = lines.length - 1; i >= 0; i--) {
        csvWriter.append(lines[i]).append("\n");
    }

    csvWriter.flush();
    csvWriter.close();
}


private static void stepInto(JSONObject jsonObject) {
    for (String key: jsonObject.keySet()) {
        Object object = jsonObject.get(key);
        if (object instanceof JSONObject) {
            builder.append(key).append(".");
            stepInto(jsonObject.getJSONObject(key));
        } else {
            builder.append(key).append(",").append(object).append("\n");
            jsonObject.remove(key);
            break;
        }

        if (jsonObject.getJSONObject(key).isEmpty()) {
            jsonObject.remove(key);
        }
        break;
    }
}