Używam biblioteki JSON podanej tutaj http://www.json.org/java/index.html, aby przekonwertować ciąg json, który mam, na CSV. Ale problem jaki mam w tym, że kolejność kluczy gubi się po konwersji.
To jest kod konwersji:
JSONObject jo = new JSONObject(someString);
JSONArray ja = jo.getJSONArray("items");
String s = CDL.toString(ja);
System.out.println(s);
Oto zawartość „someString”:
{
"items":
[
{
"WR":"qwe",
"QU":"asd",
"QA":"end",
"WO":"hasd",
"NO":"qwer"
},
]
}
Oto wynik:
WO,QU,WR,QA,NO
hasd,asd,qwe,end,qwer
Podczas gdy to, czego oczekuję, to zachowanie kolejności kluczy:
WR,QU,QA,WO,NO
qwe,asd,end,hasd,qwer
Czy jest jakiś sposób, aby uzyskać ten wynik przy użyciu tej biblioteki? Jeśli nie, to czy istnieje inna biblioteka, która zapewni możliwość zachowania kolejności kluczy w wyniku?
foo
przed kluczem,bar
a czasamibar
przedfoo
. Utrudnia to pisanie testów.Odpowiedzi:
Są (hackowe) sposoby, aby to zrobić ... ale nie powinieneś.
W JSON obiekt definiuje się następująco:
Zobacz http://json.org .
Większość implementacji JSON nie stara się zachować kolejności par nazwa / wartość obiektu, ponieważ jest ona (z definicji) nieistotna.
Jeśli chcesz zachować porządek, musisz przedefiniować strukturę danych; na przykład
{ "items": [ [ {"WR":"qwe"}, {"QU":"asd"}, {"QA":"end"}, {"WO":"hasd"}, {"NO":"qwer"} ], ] }
lub prościej:
{ "items": [ {"WR":"qwe"}, {"QU":"asd"}, {"QA":"end"}, {"WO":"hasd"}, {"NO":"qwer"} ] }
FOLLOWUP
Musisz przeprowadzić trudną rozmowę z kimkolwiek, kto zaprojektował tę strukturę plików i nie pozwoli ci jej zmienić. To jest / oni są po prostu błędne. Ci potrzeba , aby ich przekonać.
Jeśli naprawdę nie pozwolą ci tego zmienić:
Takie rzeczy są naprawdę złe. Z jednej strony Twoje oprogramowanie będzie naruszać dobrze ugruntowaną / długotrwałą specyfikację, której celem jest promowanie interoperacyjności. Z drugiej strony, głupcy, którzy zaprojektowali ten kiepski (nie JSON!) Format pliku, prawdopodobnie obrzucają systemy innych ludzi itp., Ponieważ systemy nie radzą sobie z ich bzdurami.
AKTUALIZACJA
Warto też przeczytać, co mówi na ten temat JSON RFC (RFC 7159) . Oto kilka fragmentów:
źródło
Utrzymanie porządku jest dość proste. Miałem ten sam problem z utrzymaniem kolejności z warstwy DB do warstwy interfejsu użytkownika.
Otwórz plik JSONObject.java. Wewnętrznie używa HashMap, który nie utrzymuje kolejności.
Zmień to na LinkedHashMap:
//this.map = new HashMap(); this.map = new LinkedHashMap();
To zadziałało dla mnie. Dajcie znać w komentarzach. Sugeruję, że sama biblioteka JSON powinna mieć inną klasę JSONObject, która utrzymuje porządek, jak JSONOrderdObject.java. Jestem bardzo ubogi w wyborze nazwisk.
źródło
this.map = new LinkedHashMap<String, Object>();
nadal nie działa. Proszę pomóż ?JSONObject.java
bierze podaną mapę. Może byćLinkedHashMap
lubTreeMap
i zajmie tohashmap
tylko wtedy, gdy mapa jest pusta.Oto konstruktor
JSONObject.java
klasy, który będzie sprawdzał mapę.public JSONObject(Map paramMap) { this.map = (paramMap == null ? new HashMap() : paramMap); }
Więc przed utworzeniem konstrukcji obiektu json
LinkedHashMap
i przekazaniem jej do konstruktora w ten sposób,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));
Nie ma więc potrzeby zmiany
JSONObject.java
klasy. Mam nadzieję, że to komuś pomoże.źródło
JSONObject
nie jest zamówione jako mojeLinkedHashMap
. Czy korzystasz zorg.json
lib?org.json
jedyny. DefiniujeHashMap
wewnętrznie, cokolwiek muMap
dasz: @Deepak Czy możesz wskazać nam implementację, z której korzystałeś?org.json
biblioteką. Kiedy konstruujesz nowyJSONObject
obiekt, przekazując mapę jako argument, zawsze zostanie on przekonwertowany na plikHashMap
. Konstruktor najpierw tworzy nową mapę:,this.map = new HashMap<String, Object>();
a następnie wykonuje pętlę nad twoją mapą, kopiując każdy element do swojegoHashMap
.Bardziej rozwlekłym, ale szeroko stosowanym rozwiązaniem tego rodzaju problemu jest użycie pary struktur danych: listy zawierającej uporządkowanie i mapy zawierającej relacje.
Na przykład:
{ "items": [ { "WR":"qwe", "QU":"asd", "QA":"end", "WO":"hasd", "NO":"qwer" }, ], "itemOrder": ["WR", "QU", "QA", "WO", "NO"] }
Iterujesz listę itemOrder i używasz ich do wyszukiwania wartości mapy. Porządkowanie jest zachowane, bez kłopotów.
Wielokrotnie korzystałem z tej metody.
źródło
Kolejne hackerskie rozwiązanie wykorzystujące 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
źródło
Apache Wink zamówiłJSONObject . Zachowuje kolejność podczas analizowania ciągu.
źródło
Właśnie natknąłem się na ten sam problem, uważam, że ostateczne rozwiązanie zastosowane przez autora polegało na użyciu niestandardowego 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; }
patrz http://juliusdavies.ca/json-simple-1.1.1-javadocs/org/json/simple/parser/JSONParser.html#parse(java.io.Reader,org.json.simple.parser.ContainerFactory)
źródło
Rozwiązany.
Użyłem biblioteki JSON.simple stąd https://code.google.com/p/json-simple/, aby przeczytać ciąg JSON, aby zachować kolejność kluczy i użyć biblioteki JavaCSV stąd http://sourceforge.net/ projekty / javacsv / do konwersji do formatu CSV.
źródło
org.json
konwersjiList<LinkedHahMap>
doJSONArray
, aby utworzyć plikCSV
,CSV
jest tworzony, ale nie w tej samej kolejności, co mójList
. Próbowałem użyć dwóch bibliotek, które tu przedstawiłeś, ale nie mogłem znaleźć metod konwersji na.CSV
Czy mógłbyś podać więcej szczegółów.Wiem, że to zostało rozwiązane i pytanie zostało zadane dawno temu, ale ponieważ mam do czynienia z podobnym problemem, chciałbym przedstawić zupełnie inne podejście do tego:
W przypadku tablic mówi: „Tablica to uporządkowany zbiór wartości”. na http://www.json.org/ - ale obiekty („Obiekt jest nieuporządkowanym zbiorem par nazwa / wartość”) nie są uporządkowane.
Zastanawiam się, dlaczego ten obiekt jest w tablicy - to sugeruje, że nie ma takiego porządku.
{ "items": [ { "WR":"qwe", "QU":"asd", "QA":"end", "WO":"hasd", "NO":"qwer" }, ] }
Zatem rozwiązaniem byłoby umieszczenie kluczy w „prawdziwej” tablicy i dodanie danych jako obiektów do każdego klucza, w następujący sposób:
{ "items": [ {"WR": {"data": "qwe"}}, {"QU": {"data": "asd"}}, {"QA": {"data": "end"}}, {"WO": {"data": "hasd"}}, {"NO": {"data": "qwer"}} ] }
Jest to więc podejście, które próbuje ponownie przemyśleć oryginalny model i jego założenia. Ale nie testowałem (i zastanawiam się), czy wszystkie zaangażowane narzędzia zachowałyby kolejność tej oryginalnej tablicy JSON.
źródło
W prawdziwym świecie aplikacja prawie zawsze będzie miała komponent bean Java lub domenę, która ma być serializowana / deserializowana do / z formatu JSON. Jak już wspomniano, specyfikacja obiektu JSON nie gwarantuje porządku, a wszelkie manipulacje przy tym zachowaniu nie uzasadniają tego wymagania. W mojej aplikacji miałem ten sam scenariusz, w którym musiałem zachować porządek tylko ze względu na worek czytelności. Użyłem standardowego sposobu Jacksona, aby serializować moje ziarno Java do JSON:
Object object = getObject(); //the source java bean that needs conversion String jsonString = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(object);
Aby utworzyć json z uporządkowanym zestawem elementów, po prostu używam adnotacji właściwości JSON w komponencie bean Java, którego użyłem do konwersji. Przykład poniżej:
@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 }
zastosowana powyżej getObject ():
public SampleBean getObject(){ SampleBean bean = new SampleBean(); bean.setId("100"); bean.setName("SomeName"); bean.setCity("SomeCity"); bean.setPhone("1234567890"); return bean; }
Dane wyjściowe są wyświetlane zgodnie z adnotacją kolejności właściwości Json:
{ name: "SomeName", phone: "1234567890", city: "SomeCity", id: 100 }
źródło
Najbezpieczniejszym sposobem jest prawdopodobnie nadpisywanie kluczy, które są używane do generowania danych wyjściowych:
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(); } };
źródło
patchFor (answer @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()) {
źródło
Możesz użyć następującego kodu, aby wykonać niestandardową serializację ZAMÓWIONĄ i deserializację tablicy JSON (w tym przykładzie założono, że zamawiasz ciągi, ale można go zastosować do wszystkich typów):
Serializacja
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);
Deserializacja
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); } } } }
źródło
Twój przykład:
{ "items": [ { "WR":"qwe", "QU":"asd", "QA":"end", "WO":"hasd", "NO":"qwer" }, ... ] }
dodaj element „itemorder”
{ "items": [ { "WR":"qwe", "QU":"asd", "QA":"end", "WO":"hasd", "NO":"qwer" }, ... ], "itemorder":["WR","QU","QA","WO","NO"] }
Ten kod generuje żądane dane wyjściowe bez wiersza tytułu kolumny:
JSONObject output = new JSONObject(json); JSONArray docs = output.getJSONArray("data"); JSONArray names = output.getJSONArray("itemOrder"); String csv = CDL.toString(names,docs);
źródło
zamiast używać jsonObject spróbuj użyć CsvSchema w ten sposób łatwiej i bezpośrednio konwertuje obiekt na csv
i mentains id zamówić pojo ma @JsonPropertyOrder w nim
źródło
Underscore-java zachowuje zamówienia na elementy podczas odczytu json. Jestem opiekunem projektu.
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}]}
źródło
Przetestowałem rozwiązanie mrugnięcia i działa dobrze:
@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()); }
źródło