[java] JSON을 CSV로 변환하는 동안 JSON 키의 순서 유지

여기에 제공된 JSON 라이브러리 http://www.json.org/java/index.html 을 사용하여 필요한 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은 매우 널리 사용되었습니다. 이 경험을 통해 특정 패턴이 드러났지만 사양에 따라 허용되지만 상호 운용성 문제가 발생했습니다.

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

JSON은 네 가지 기본 유형 (문자열, 숫자, 부울 및 널)과 두 가지 구조화 된 유형 (객체 및 배열)을 나타낼 수 있습니다.

개체는 0 개 이상의 이름 / 값 쌍 의 순서지정되지 않은 컬렉션입니다. 여기서 이름은 문자열이고 값은 문자열, 숫자, 부울, null, 개체 또는 배열입니다.

JSON 구문 분석 라이브러리는 호출 소프트웨어에 개체 멤버의 순서를 표시하는지 여부가 다른 것으로 관찰되었습니다. 동작이 멤버 순서에 의존하지 않는 구현은 이러한 차이의 영향을받지 않는다는 점에서 상호 운용이 가능합니다.


답변

질서를 유지하는 것은 아주 간단합니다. DB 레이어에서 UI 레이어로 순서를 유지하는 데 동일한 문제가 발생했습니다.

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

LinkedHashMap으로 변경하십시오.

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

이것은 나를 위해 일했습니다. 댓글로 알려주세요. JSON 라이브러리 자체에는 JSONOrderdObject.java와 같이 순서를 유지하는 또 다른 JSONObject 클래스가 있어야합니다. 나는 이름을 선택하는 데 매우 가난합니다.


답변

JSONObject.java어떤지도를 통과하든 가져갑니다. LinkedHashMap또는 일 수 있으며 맵이 null 인 경우에만 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클래스 를 변경할 필요가 없습니다 . 누군가에게 도움이되기를 바랍니다.


답변

이러한 종류의 문제에 대해보다 장황하지만 광범위하게 적용 할 수있는 해결책은 한 쌍의 데이터 구조를 사용하는 것입니다. 순서를 포함하는 목록과 관계를 포함하는 맵입니다.

예를 들면 :

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

itemOrder 목록을 반복하고이를 사용하여 맵 값을 조회합니다. kludges없이 주문이 보존됩니다.

이 방법을 여러 번 사용했습니다.


답변

reflect를 사용하는 또 다른 해키 솔루션 :

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


답변

Apache Wink에는 OrderedJSONObject가 있습니다. 문자열을 구문 분석하는 동안 순서를 유지합니다.


답변

같은 문제를 만났을 때 저자가 사용한 최종 솔루션은 사용자 정의 ContainerFactory를 사용하는 것으로 구성되었다고 생각합니다.

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) 참조