source

JSON을 CSV로 변환하는 동안 JSON 키의 순서를 유지합니다.

lovecheck 2023. 3. 8. 21:17
반응형

JSON을 CSV로 변환하는 동안 JSON 키의 순서를 유지합니다.

http://www.json.org/java/index.html에 있는 JSON 라이브러리를 사용하여 json 문자열을 CSV로 변환합니다.하지만 문제는 변환 후 키의 순서가 손실된다는 것입니다.

변환 코드는 다음과 같습니다.

    JSONObject jo = new JSONObject(someString);
    JSONArray ja = jo.getJSONArray("items");
    String s = CDL.toString(ja);
    System.out.println(s);

다음은 "someString"의 내용입니다.

{
    "items":
    [
        {
            "WR":"qwe",
            "QU":"asd",
            "QA":"end",
            "WO":"hasd",
            "NO":"qwer"
        },
    ]
}

결과는 다음과 같습니다.

WO,QU,WR,QA,NO
hasd,asd,qwe,end,qwer

내가 기대하는 것은 키의 순서를 유지하는 것이다.

WR,QU,QA,WO,NO
qwe,asd,end,hasd,qwer

이 라이브러리를 사용하여 이 결과를 얻을 수 있는 방법이 있습니까?그렇지 않은 경우 결과에서 키의 순서를 유지하는 기능을 제공하는 다른 라이브러리가 있습니까?

방법은 여러 가지가 있지만...그러면 안 된다.

JSON에서는 오브젝트는 다음과 같이 정의됩니다.

개체는 이름/값 쌍의 순서가 정렬되지 않은 집합입니다.

http://json.org 를 참조해 주세요.

JSON의 대부분의 구현에서는 객체 이름/값 쌍의 순서가 중요하지 않기 때문에 이 순서는 유지되지 않습니다.

순서를 유지하려면 데이터 구조를 다시 정의해야 합니다.

{
    "items":
    [
        [
            {"WR":"qwe"},
            {"QU":"asd"},
            {"QA":"end"},
            {"WO":"hasd"},
            {"NO":"qwer"}
        ],
    ]
}

또는 더 간단하게:

{
    "items":
    [
        {"WR":"qwe"},
        {"QU":"asd"},
        {"QA":"end"},
        {"WO":"hasd"},
        {"NO":"qwer"}
    ]
}

따르다

정보 감사합니다만, 어플리케이션에서는 JSON을 사용할 수 밖에 없고, 어플리케이션에서는 JSON 오브젝트의 정의에 관계없이 키의 순서를 유지할 필요가 있습니다.JSON 파일의 포맷도 변경할 수 없습니다.

이 파일 구조를 설계한 사람이 누구인지는 몰라도 변경할 수 없도록 해야 합니다.그것은/ 그들이 명백히 틀렸다.그들을 설득해야 합니다.

정말로 변경을 허락하지 않는 경우:

  • JSON이라고 부르지 말라고...'그렇지 않으니까.
  • 이 "JSON이 아닌" 형식을 처리하려면 특별히 코드를 작성/수정해야 합니다.순서를 보존하는 JSON 실장을 찾을 수 없는 경우는 제외합니다.만약 그들이 유료 고객이라면, 당신이 해야 할 추가 작업에 대한 비용을 그들이 지불하는지 확인하세요.
  • 다른 툴에서 "not JSON"을 사용해야 하는 경우 문제가 발생한다는 점을 지적해야 합니다.실제로 이 문제는 몇 번이고 반복됩니다.

이런 건 정말 안 좋아한편, 사용의 소프트웨어는, 상호 운용성을 촉진하기 위해서 설계된, 확립된 규격이나 장기 사양에 위반됩니다.한편, 이 어설픈 파일 포맷(JSON이 아님)을 설계한 멍청이들은 시스템이 자신의 난센스에 대처할 수 없기 때문에 다른 사람의 시스템 등을 혹평하고 있을 것입니다.

갱신하다

주제에 관한 JSON RFC(RFC 7159)의 설명도 읽어볼 필요가 있습니다.다음은 발췌한 내용입니다.

RFC 4627이 발표된 이후 수년간 JSON은 매우 광범위하게 사용되고 있습니다.이 경험으로 인해 특정 패턴이 드러났으며, 이러한 패턴은 사양상 허용되지만 상호 운용성 문제가 발생하고 있습니다.

JavaScript Object Notation(JSON)은 구조화된 데이터의 직렬화를 위한 텍스트 형식입니다.

JSON은 4개의 기본 유형(스트링, 숫자, 부울 및 늘)과 2개의 구조화 유형(객체와 배열)을 나타낼 수 있습니다.

개체는 0개 이상의 이름/값 쌍의 순서가 없는 집합입니다. 여기서 name은 문자열이고 value는 문자열, number, boolean, null, object 또는 배열입니다.

JSON 해석 라이브러리는 오브젝트 멤버의 순서를 호출 소프트웨어에 표시할 수 있는지 여부에 대해 다른 것으로 확인되었습니다.멤버의 순서에 의존하지 않는 실장은 이러한 차이의 영향을 받지 않는다는 점에서 상호 운용이 가능합니다.

질서를 유지하는 것은 꽤 간단하다.DB 계층에서 UI 계층으로 순서를 유지하는 데 있어서도 같은 문제가 있었습니다.

JSONObject.java 파일을 엽니다.내부적으로 순서를 유지하지 않는 HashMap을 사용합니다.

Linked Hash Map으로 변경합니다.

    //this.map = new HashMap();
    this.map = new LinkedHashMap();

이건 나한테 효과가 있었어.댓글로 알려주세요.JSON 라이브러리 자체에 순서를 유지하는 다른 JSONObject 클래스가 있어야 합니다(JSONOrderdObject.java).나는 이름 고르는 것이 매우 서툴러요.

JSONObject.java그럴 도 있어요.LinkedHashMap ★★★★★★★★★★★★★★★★★」TreeMap 하면 된다hashmap맵이 늘일 경우에만.

다음은 의 구축자입니다.JSONObject.java지도 검사를 하는 클래스입니다.

 public JSONObject(Map paramMap)
  {
    this.map = (paramMap == null ? new HashMap() : paramMap);
  }

에 json을 구축합니다.LinkedHashMap하면 됩니다.

LinkedHashMap<String, String> jsonOrderedMap = new LinkedHashMap<String, String>();

jsonOrderedMap.put("1","red");
jsonOrderedMap.put("2","blue");
jsonOrderedMap.put("3","green");

JSONObject orderedJson = new JSONObject(jsonOrderedMap);

JSONArray jsonArray = new JSONArray(Arrays.asList(orderedJson));

System.out.println("Ordered JSON Fianl CSV :: "+CDL.toString(jsonArray));

때문에 굳이 .JSONObject.java .class.disclass.disclass그게 누군가에게 도움이 되길 바란다.

리플렉트를 사용한 또 다른 해킹 솔루션:

JSONObject json = new JSONObject();
Field map = json.getClass().getDeclaredField("map");
map.setAccessible(true);//because the field is private final...
map.set(json, new LinkedHashMap<>());
map.setAccessible(false);//return flag

이러한 문제에 대한 보다 상세하지만 광범위하게 적용할 수 있는 해결책은 데이터 구조 쌍(순서를 포함하는 목록과 관계를 포함하는 지도)을 사용하는 것입니다.

예:

{
    "items":
    [
        {
            "WR":"qwe",
            "QU":"asd",
            "QA":"end",
            "WO":"hasd",
            "NO":"qwer"
        },
    ],
    "itemOrder":
        ["WR", "QU", "QA", "WO", "NO"]
}

itemOrder 목록을 반복하여 맵 값을 검색합니다.주문은 유지되며, Krudge가 없습니다.

나는 이 방법을 여러 번 사용해 왔다.

Apache Wink가 주문 완료JSONObject.String을 해석하는 동안 순서를 유지합니다.

방금 같은 문제를 발견했습니다.저자가 사용한 최종 솔루션은 커스텀 Container Factory를 사용하는 것이라고 생각합니다.

public static Values parseJSONToMap(String msgData) {
    JSONParser parser = new JSONParser();
    ContainerFactory containerFactory = new ContainerFactory(){
        @Override
        public Map createObjectContainer() {
            return new LinkedHashMap();
        }

        @Override
        public List creatArrayContainer() {
            return null;
        }
    };
    try {
        return (Map<String,Object>)parser.parse(msgData, containerFactory);
    } catch (ParseException e) {
        log.warn("Exception parsing JSON string {}", msgData, e);
    }
    return null;
}  

http://juliusdavies.ca/json-simple-1.1.1-javadocs/org/json/simple/parser/JSONParser.html#parse(java.io.Reader,org.json.simple.parser.ContainerFactory) 를 참조해 주세요.

해결된.

여기 https://code.google.com/p/json-simple/의 JSON.simple 라이브러리를 사용하여 키의 순서를 유지하는 JSON 문자열을 읽고 여기 http://sourceforge.net/projects/javacsv/의 JavaCSV 라이브러리를 사용하여 CSV 형식으로 변환했습니다.

실제로 어플리케이션에는 거의 항상 JSON과 시리얼화/디시리얼라이즈되는 Java bean 또는 도메인이 있습니다.JSON 오브젝트 사양이 순서를 보증하는 것은 아니며, 그 동작을 조작한다고 해서 요건이 정당화되는 것은 아닙니다.내 어플리케이션에서도 읽기 쉽도록 순서를 유지해야 하는 시나리오가 있었습니다.JSON에 java bean을 시리얼화하기 위해 표준 잭슨 방식을 사용했습니다.

Object object = getObject();  //the source java bean that needs conversion
String jsonString = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(object);

요소의 순서가 매겨진 json을 만들기 위해서는 변환에 사용한 Java bean의 jSON 속성 주석을 사용합니다.다음은 예를 제시하겠습니다.

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"name","phone","city","id"})
public class SampleBean implements Serializable {
    private int id;
    private String name:
    private String city;
    private String phone;

    //...standard getters and setters
}

위의 getObject()를 사용합니다.

public SampleBean getObject(){
    SampleBean bean  = new SampleBean();
    bean.setId("100");
    bean.setName("SomeName");
    bean.setCity("SomeCity");
    bean.setPhone("1234567890");
    return bean;
}

출력은 Json 속성 순서 주석과 같이 표시됩니다.

{
    name: "SomeName",
    phone: "1234567890",
    city: "SomeCity",
    id: 100
}

이 문제가 해결되고 오래 전에 질문이 제기되었다는 것은 알지만, 저는 비슷한 문제를 다루고 있기 때문에 이에 대해 전혀 다른 접근방식을 제안하고 싶습니다.

어레이의 경우 http://www.json.org/에 "Array는 값의 순서부여 집합입니다."라고 표시되지만 객체("개체는 이름/값 쌍의 순서부여 집합입니다")는 순서가 매겨지지 않습니다.

나는 왜 그 물체가 배열에 있는지 궁금하다 - 그것은 존재하지 않는 질서를 암시한다.

{
"items":
[
    {
        "WR":"qwe",
        "QU":"asd",
        "QA":"end",
        "WO":"hasd",
        "NO":"qwer"
    },
]
}

따라서 다음과 같이 키를 "실제" 배열에 배치하고 데이터를 개체로 각 키에 추가하는 방법이 있습니다.

{
"items":
[
    {"WR": {"data": "qwe"}},
    {"QU": {"data": "asd"}},
    {"QA": {"data": "end"}},
    {"WO": {"data": "hasd"}},
    {"NO": {"data": "qwer"}}
]
}

따라서 이것은 원래 모델링과 그 의도를 재고하려는 접근법입니다.그러나 관련된 모든 툴이 원래 JSON 어레이의 순서를 유지할 수 있을지는 테스트하지 않았습니다.

언더스코어-자바는 json을 읽는 동안 요소의 순서를 유지합니다.

String json = "{\n"
      + "    \"items\":\n"
      + "    [\n"
      + "        {\n"
      + "            \"WR\":\"qwe\",\n"
      + "            \"QU\":\"asd\",\n"
      + "            \"QA\":\"end\",\n"
      + "            \"WO\":\"hasd\",\n"
      + "            \"NO\":\"qwer\"\n"
      + "        }\n"
      + "    ]\n"
      + "}";
System.out.println(U.fromJson(json));

// {items=[{WR=qwe, QU=asd, QA=end, WO=hasd, NO=qwer}]}

patch For(응답 @gary):

$ git diff JSONObject.java                                                         
diff --git a/JSONObject.java b/JSONObject.java
index e28c9cd..e12b7a0 100755
--- a/JSONObject.java
+++ b/JSONObject.java
@@ -32,7 +32,7 @@ import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.Collection;
 import java.util.Enumeration;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
@@ -152,7 +152,9 @@ public class JSONObject {
      * Construct an empty JSONObject.
      */
     public JSONObject() {
-        this.map = new HashMap<String, Object>();
+//      this.map = new HashMap<String, Object>();
+        // I want to keep order of the given data:
+        this.map = new LinkedHashMap<String, Object>();
     }

     /**
@@ -243,7 +245,7 @@ public class JSONObject {
      * @throws JSONException
      */
     public JSONObject(Map<String, Object> map) {
-        this.map = new HashMap<String, Object>();
+        this.map = new LinkedHashMap<String, Object>();
         if (map != null) {
             Iterator<Entry<String, Object>> i = map.entrySet().iterator();
             while (i.hasNext()) {

다음 코드를 사용하여 JSON 어레이의 커스텀 ORDERED 시리얼라이제이션 및 디시리얼라이제이션(이 예에서는 Strings를 주문하고 있지만 모든 유형에 적용할 수 있습니다)을 실행할 수 있습니다.

시리얼화

JSONArray params = new JSONArray();
int paramIndex = 0;

for (String currParam : mParams)
{
    JSONObject paramObject = new JSONObject();
    paramObject.put("index", paramIndex);
    paramObject.put("value", currParam);

    params.put(paramObject);
    ++paramIndex;
}

json.put("orderedArray", params);

역직렬화

JSONArray paramsJsonArray = json.optJSONArray("orderedArray");
if (null != paramsJsonArray)
{
    ArrayList<String> paramsArr = new ArrayList<>();
    for (int i = 0; i < paramsJsonArray.length(); i++)
    {
        JSONObject param = paramsJsonArray.optJSONObject(i);
        if (null != param)
        {
            int paramIndex = param.optInt("index", -1);
            String paramValue = param.optString("value", null);

            if (paramIndex > -1 && null != paramValue)
            {
                paramsArr.add(paramIndex, paramValue);
            }
        }
    }
}

예:

{
    "items":
    [
        {
            "WR":"qwe",
            "QU":"asd",
            "QA":"end",
            "WO":"hasd",
            "NO":"qwer"
        },
        ...
    ]
}

요소 "itemorder" 추가

{
    "items":
    [
        {
            "WR":"qwe",
            "QU":"asd",
            "QA":"end",
            "WO":"hasd",
            "NO":"qwer"
        },
        ...
    ],
    "itemorder":["WR","QU","QA","WO","NO"]
}

이 코드는 열 제목 행 없이 원하는 출력을 생성합니다.

JSONObject output = new JSONObject(json);
JSONArray docs = output.getJSONArray("data");
JSONArray names = output.getJSONArray("itemOrder");
String csv = CDL.toString(names,docs);

jsonObject를 사용하는 대신 CsvSchema를 사용하여 개체를 csv로 직접 변환해 보십시오.

CsvSchema schema = csvMapper.schemaFor(MyClass.class).withHeader();
        csvMapper.writer(schema).writeValueAsString(myClassList);

Pojo가 @JsonPropertyOrder에 포함된 주문 ID를 나타냅니다.

사용할 수 있습니다.

toString(JSONArray names, JSONArray ja)

json 배열과 같은 순서로 제공된 이름 목록을 사용하여 JSONObjects의 JSONArray에서 쉼표로 구분된 텍스트를 생성합니다.

참조: https://stleary.github.io/JSON-java/org/json/CDL.html#toString-org.json.JSONArray-org.json.JSONArray-

가장 안전한 방법은 출력 생성에 사용되는 키 방식을 덮어쓰는 것입니다.

new JSONObject(){
  @Override
  public Iterator keys(){
    TreeSet<Object> sortedKeys = new TreeSet<Object>();
    Iterator keys = super.keys();
    while(keys.hasNext()){
      sortedKeys.add(keys.next());
    }
    return sortedKeys.iterator();
  }
};

윙크 솔루션을 테스트하여 정상적으로 동작:

@Test
public void testJSONObject() {
    JSONObject jsonObject = new JSONObject();
    jsonObject.put("bbb", "xxx");
    jsonObject.put("ccc", "xxx");
    jsonObject.put("aaa", "xxx");
    jsonObject.put("xxx", "xxx");
    System.out.println(jsonObject.toString());
    assertTrue(jsonObject.toString().startsWith("{\"xxx\":"));
}

@Test
public void testWinkJSONObject() throws JSONException {
    org.apache.wink.json4j.JSONObject jsonObject = new OrderedJSONObject();
    jsonObject.put("bbb", "xxx");
    jsonObject.put("ccc", "xxx");
    jsonObject.put("aaa", "xxx");
    jsonObject.put("xxx", "xxx");
    assertEquals("{\"bbb\":\"xxx\",\"ccc\":\"xxx\",\"aaa\":\"xxx\",\"xxx\":\"xxx\"}", jsonObject.toString());
}

언급URL : https://stackoverflow.com/questions/4515676/keep-the-order-of-the-json-keys-during-json-conversion-to-csv

반응형