【问题标题】:How to convert csv To nested Json in java?如何在java中将csv转换为嵌套的Json?
【发布时间】:2019-11-14 14:40:08
【问题描述】:

我有一个以下格式的 csv 文件

A_aa,A_ab,A_ac,A_ad,B_BB_ba,B_BB_BBB_bb
1,2,3,4,5,6

我想把它转换成下面的嵌套 json

{
   'A':{
        'aa' : '1',
        'ab' : '2',
        'ac' : '4',
        'ad' : '5',
    }
    'B':{
        'BB':{
            'ba' : '5',
            'BBB':{
                'bb' : '6'
            }
        }
    }
}

【问题讨论】:

  • 你的 JSON 字符串无效,字符串应该用双引号括起来。

标签: java json csv


【解决方案1】:

我给你写了部分解决方案。请使用maven依赖

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.0</version>
</dependency>

java类:

package com.mycompany.app;
import com.google.gson.Gson;

public class Car 
{
    public A A;
    public B B;


    public A getA()
    {
        return A;
    }


    public void setA(A a)
    {
        this.A = a;
    }


    public B getB()
    {
        return B;
    }


    public void setB(B b)
    {
        this.B = b;
    }


    public class A {
        String aa;
        String ab;
        String ac;
        String ad;
        public String getAa()
        {
            return aa;
        }
        public void setAa(String aa)
        {
            this.aa = aa;
        }
        public String getAb()
        {
            return ab;
        }
        public void setAb(String ab)
        {
            this.ab = ab;
        }
        public String getAc()
        {
            return ac;
        }
        public void setAc(String ac)
        {
            this.ac = ac;
        }
        public String getAd()
        {
            return ad;
        }
        public void setAd(String ad)
        {
            this.ad = ad;
        }   

    }

    public class B {
        public BB BB;


        public BB getBb()
        {
            return BB;
        }


        public void setBb(BB bb)
        {
            this.BB = bb;
        }



        public class BB {
            String ba;
            public BBB BBB;

            public String getBa()
            {
                return ba;
            }

            public void setBa(String ba)
            {
                this.ba = ba;
            }

            public BBB getBbb()
            {
                return BBB;
            }

            public void setBbb(BBB bbb)
            {
                this.BBB = bbb;
            }

            public class BBB {
                public String bb;

                public String getBb()
                {
                    return bb;
                }

                public void setBb(String bb)
                {
                    this.bb = bb;
                }               

            }

        }

    }


    public static void main(String[] args) 
    {   
    String line1="A_aa,A_ab,A_ac,A_ad,B_BB_ba,B_BB_BBB_bb";
    String line2="1,2,3,4,5,6";

    String[] partsLinke1 = line1.split(",");
    String[] partsLinke2 = line2.split(",");
    Car c=new Car();
    Gson gson = new Gson();


    int k=0;

    for(int i=0; i<partsLinke1.length; i++) {
        System.out.println(partsLinke1[i]);
        String[] parts=partsLinke1[i].split("_");
        for(int j=0; j<parts.length; j++) {
            System.out.println(parts[j]);
            if(parts[j].equals("A")) {

                Car.A aJson=c.new A();

                if(parts[j+1].equals("aa")) {

                    aJson.setAa(partsLinke2[k]);
                    c.setA(aJson);
                }

            }


        }

    }
    String json = gson.toJson(c);
    System.out.println(json);

    }
}

和输出:

A_aa
A
aa
A_ab
A
ab
A_ac
A
ac
A_ad
A
ad
B_BB_ba
B
BB
ba
B_BB_BBB_bb
B
BB
BBB
bb
{"A":{"aa":"1"}}

我想你现在写剩下的会更容易;)

【讨论】:

    【解决方案2】:

    您的问题可以分为2个子问题。
    Q1:如何将下划线('_')分隔的字符串模式转换为嵌套映射。因为一旦实现了这一点,您就可以使用任何一种最流行的 Json 库(例如 JacksonGson)将映射转换为 JSON 字符串,
    Q2:如何解析CSV 文件。我想已经有很多文章讨论过这个问题。

    对于第一个子问题,受@Andreas 在Generate Nested Map from Path String in Java 中的回答启发,可以使用以下函数解决问题:

    public static void generateNestedMap(Map<String, Object> map, String path, Object value) {
        int start = 0;
        for (int end; (end = path.indexOf('_', start)) != -1; start = end + 1)
            map = (Map<String, Object>) map.computeIfAbsent(path.substring(start, end), k -> new HashMap<String, Object>());
        map.put(path.substring(start), value);
    }
    

    然后您可以将给定的字符串和相应的值存储在映射中,Map&lt;String, Object&gt; result 如下所示:

    代码 sn-p

    Map<String, Object> result = new HashMap<>();
    generateNestedMap(result, "A_aa", 1);
    generateNestedMap(result, "A_ab", 2);
    generateNestedMap(result, "A_ac", 3);
    generateNestedMap(result, "A_ad", 4);
    generateNestedMap(result, "B_BB_ba", 5);
    generateNestedMap(result, "B_BB_BBB_bb", 6);
    System.out.println(result.toString());
    

    控制台输出

    {A={aa=1, ab=2, ac=3, ad=4}, B={BB={BBB={bb=6}, ba=5}}}

    之后,您可以使用Jackson 库轻松地将地图转换为 JSON 字符串,如下所示:

    ObjectMapper mapper = new ObjectMapper();
    String jsonStr = mapper.writeValueAsString(result);
    System.out.println(jsonStr);
    

    它的输出应该是:

    {"A":{"aa":1,"ab":2,"ac":3,"ad":4},"B":{"BB":{"BBB":{" bb":6},"ba":5}}}

    对于第二个子问题,也有很多库如OpenCSVApache Commons CSV 可以处理这个问题,我不再赘述。

    【讨论】:

      【解决方案3】:

      首先,拆分两行得到一个names和一个values数组:

          String line1 = "A_aa,A_ab,A_ac,A_ad,B_BB_ba,B_BB_BBB_bb";
          String line2 = "1,2,3,4,5,6";
      
          String[] names = line1.split(",");
          String[] values = line2.split(",");
      

      创建Maps 的结构并将每个名称/值对添加到其中:

          Map<String,Object> root = new HashMap<>();
          for (int i = 0; i < names.length; ++i) {
              String name = names[i];
              String value = values[i];
              addValue(root, name.split("_"), value);
          }
      

      方法addValue 如下所示:

      private static void addValue(Map<String,Object> map, String[] path,
              String value) {
          for (int i = 0; i < path.length-1; ++i) {
              String elem = path[i];
              Object current = map.get(elem);
              Map<String,Object> map2;
              if (current instanceof Map) {
                  map2 = (Map<String,Object>)map.get(elem);
              } else {
                  map2 = new HashMap<>();
                  map.put(elem, map2);
              }
              map = map2;
          }
          map.put(path[path.length-1], value);
      }
      

      最后,将结构转换为 JSON。这里使用了 Gson 库:

          Gson gson = new GsonBuilder().setPrettyPrinting().create();
          gson.toJson(root, System.out);
      

      【讨论】:

        【解决方案4】:

        CSV文件的第一行包含字段标题(下划线用于表示层次关系。详细数据从第二行开始。您需要将CSV转换为JSON。难点在于动态解析,因为它涉及分组、递归、循环、条件判断和字符串连接。如果你尝试使用Java来完成你的任务,代码会很长。

        使用开源 Java 包 SPL 很容易实现这一点。五行代码就够了:

        A B
        1 =file("json.csv").import@cw()
        2 =i=0,A1(1).(~.split("_")).(~|A1(2)(#)).(~.run(~="\""/~/"\""))
        3 func recurse(AA) >B1=left(B1,-i)/"{}"/right(B1,i),i+=1,AA.group(~(1)).(if(~.len()==1 && ~(1).len()==2,B1=left(B1,-i)/~(1).concat(":")/right(B1,i),(B1=left(B1,-i)/~(1)(1)/":"/right(B1,i),func(recurse,~.(~.m(2:))))))
        4 =func(recurse,A2)
        5 =replace(replace(B1,"\"\"","\",\""),"}\"","},\"")

        SPL 提供 JDBC 驱动程序供 Java 调用。只需将上述 SPL 脚本存储为 recurse.splx 并在调用存储过程时在 Java 中调用它:

        …
        Class.forName("com.esproc.jdbc.InternalDriver");
        con= DriverManager.getConnection("jdbc:esproc:local://");
        st = con.prepareCall("call recurse()");
        st.execute();
        …
        

        【讨论】:

          猜你喜欢
          • 2021-10-21
          • 2014-09-06
          • 2013-08-03
          • 1970-01-01
          • 1970-01-01
          • 2022-08-21
          • 2018-01-07
          • 2020-10-28
          相关资源
          最近更新 更多