J'utilise la bibliothèque JSON fournie ici http://www.json.org/Java/index.html pour convertir une chaîne json que je dois au format CSV . Mais le problème que j'ai est, l'ordre de les clés sont perdues après la conversion.
C'est le code de conversion:
JSONObject jo = new JSONObject(someString);
JSONArray ja = jo.getJSONArray("items");
String s = CDL.toString(ja);
System.out.println(s);
C'est le contenu de "someString":
{
"items":
[
{
"WR":"qwe",
"QU":"asd",
"QA":"end",
"WO":"hasd",
"NO":"qwer"
},
]
}
Voici le résultat:
WO,QU,WR,QA,NO
hasd,asd,qwe,end,qwer
Bien que ce que je prévois est de garder l’ordre des clés:
WR,QU,QA,WO,NO
qwe,asd,end,hasd,qwer
Existe-t-il un moyen d'obtenir ce résultat en utilisant cette bibliothèque? Sinon, y a-t-il une autre bibliothèque capable de conserver l'ordre des clés dans le résultat?
Résolu.
J'ai utilisé la bibliothèque JSON.simple à partir d'ici https://code.google.com/p/json-simple/ pour lire la chaîne JSON afin de conserver l'ordre des clés et d'utiliser la bibliothèque JavaCSV ici http: //sourceforge.net/projects/javacsv/ à convertir au format CSV.
Il y a plusieurs façons de le faire ... mais vous ne devriez pas.
En JSON, un objet est défini ainsi:
Un objet est un ensemble non ordonné de paires nom/valeur.
Voir http://json.org .
La plupart des implémentations de JSON ne font aucun effort pour préserver l'ordre des paires nom/valeur d'un objet, car ce n'est (par définition) pas significatif.
Si vous souhaitez que l'ordre soit préservé, vous devez redéfinir votre structure de données. par exemple.
{
"items":
[
[
{"WR":"qwe"},
{"QU":"asd"},
{"QA":"end"},
{"WO":"hasd"},
{"NO":"qwer"}
],
]
}
ou plus simplement:
{
"items":
[
{"WR":"qwe"},
{"QU":"asd"},
{"QA":"end"},
{"WO":"hasd"},
{"NO":"qwer"}
]
}
SUIVRE
Merci pour l'info, mais je n'ai pas d'autre choix que d'utiliser JSON dans mon application et mon application doit conserver l'ordre des clés quelle que soit la définition de l'objet JSON ... Je ne suis pas autorisé à modifier le format du fichier JSON ainsi que...
Vous devez avoir une conversation difficile avec le créateur de cette structure de fichiers et ne vous laisseront pas la modifier. C'est/ils ont carrément tort. Vous devez les convaincre.
S'ils (vraiment} _ ne vous laisseront pas le changer:
Ce genre de chose est vraiment mauvais. D'une part, votre logiciel violera une spécification bien établie/établie de longue date, conçue pour promouvoir l'interopérabilité. D'un autre côté, les idiots qui ont conçu ce format de fichier boiteux (pas JSON!) Sont probablement en train de s'extasier sur les systèmes des autres, parce qu'ils ne peuvent pas gérer leurssensités.
METTRE À JOUR
Il convient également de lire ce que dit le JSON RFC (RFC 7159) à ce sujet. Voici quelques extraits:
Dans les années qui ont suivi la publication de la RFC 4627, JSON a trouvé très large utilisation. Cette expérience a révélé certains modèles qui, permise par ses spécifications, ont causé l’interopérabilité problèmes.
JavaScript Object Notation (JSON) est un format de texte pour le sérialisation des données structurées. ...
JSON peut représenter quatre types primitifs (chaînes, nombres, booléens, Et null) et deux types structurés (objets et tableaux).
Un objet est une collection unordered de zéro ou plusieurs noms/valeurs paires, où un nom est une chaîne et une valeur une chaîne, un nombre, booléen, null, objet ou tableau.
Il a été observé que les bibliothèques d'analyse JSON différaient quant à savoir si ou ils ne rendent pas visible le classement des objets par l'appel Logiciel. Implémentations dont le comportement ne dépend pas du membre la commande sera interopérable en ce sens qu'elle ne le sera pas affectés par ces différences.
C'est assez simple de maintenir l'ordre. J'ai eu le même problème avec le maintien de l'ordre de la couche DB à la couche UI.
Ouvrez le fichier JSONObject.Java. Il utilise en interne HashMap qui ne maintient pas l'ordre.
Changez-le en LinkedHashMap:
//this.map = new HashMap();
this.map = new LinkedHashMap();
Cela a fonctionné pour moi. Faites-moi savoir dans les commentaires. Je suggère que la bibliothèque JSON elle-même ait une autre classe JSONObject qui maintient l'ordre, comme JSONOrderdObject.Java. Je suis très pauvre dans le choix des noms.
JSONObject.Java
prend la carte que vous passez. Il peut s'agir de LinkedHashMap
ou TreeMap
et cela ne prendra hashmap
que lorsque la carte est nulle.
Voici le constructeur de la classe JSONObject.Java
qui effectuera la vérification de la carte.
public JSONObject(Map paramMap)
{
this.map = (paramMap == null ? new HashMap() : paramMap);
}
Donc, avant de construire un objet json, construisez LinkedHashMap
et transmettez-le ensuite au constructeur,
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));
Il n'est donc pas nécessaire de changer la classe JSONObject.Java
. J'espère que ça aide quelqu'un.
Une solution plus détaillée, mais largement applicable, à ce type de problème consiste à utiliser une paire de structures de données: une liste contenant l’ordre et une carte contenant les relations.
Par exemple:
{
"items":
[
{
"WR":"qwe",
"QU":"asd",
"QA":"end",
"WO":"hasd",
"NO":"qwer"
},
],
"itemOrder":
["WR", "QU", "QA", "WO", "NO"]
}
Vous parcourez la liste itemOrder et utilisez-la pour rechercher les valeurs de la carte. La commande est préservée, sans kludges.
J'ai utilisé cette méthode plusieurs fois.
Une autre solution de hacky utilisant 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 a OrderedJSONObject . Il conserve la commande lors de l'analyse de la chaîne.
Je suis tombé par hasard sur le même problème. Je pense que la solution finale utilisée par l’auteur consistait à utiliser un conteneur personnalisé:
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;
}
Je sais que cela est résolu et que la question a été posée il y a longtemps, mais comme je suis confronté à un problème similaire, j'aimerais donner une approche totalement différente à celle-ci:
Pour les tableaux, il est indiqué "Un tableau est une collection ordonnée de valeurs". à http://www.json.org/ - mais les objets ("Un objet est un ensemble non ordonné de paires nom/valeur.") ne sont pas ordonnés.
Je me demande pourquoi cet objet est dans un tableau - cela implique un ordre qui n'y est pas.
{
"items":
[
{
"WR":"qwe",
"QU":"asd",
"QA":"end",
"WO":"hasd",
"NO":"qwer"
},
]
}
Une solution serait donc de placer les clés dans un tableau "réel" et d’ajouter les données sous forme d’objets à chaque clé comme ceci:
{
"items":
[
{"WR": {"data": "qwe"}},
{"QU": {"data": "asd"}},
{"QA": {"data": "end"}},
{"WO": {"data": "hasd"}},
{"NO": {"data": "qwer"}}
]
}
Il s’agit donc d’une approche qui tente de repenser la modélisation originale et son objectif. Mais je n’ai pas testé (et je me demande bien) si tous les outils impliqués conserveraient l’ordre de ce tableau JSON original.
Dans le monde réel, une application aura presque toujours un bean ou un domaine Java à sérialiser/désérialiser en JSON. Il a déjà été mentionné que la spécification d'objet JSON ne garantit pas l'ordre et que toute manipulation de ce comportement ne justifie pas l'exigence. J'ai eu le même scénario dans mon application où je devais préserver l'ordre juste pour le but de la lisibilité. J'ai utilisé la méthode standard jackson pour sérialiser mon bean Java en JSON:
Object object = getObject(); //the source Java bean that needs conversion
String jsonString = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(object);
Afin de faire le json avec un ensemble ordonné d'éléments, j'utilise simplement l'annotation de propriété JSON dans le bean Java que j'ai utilisé pour la conversion. Un exemple ci-dessous:
@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
}
le getObject () utilisé ci-dessus:
public SampleBean getObject(){
SampleBean bean = new SampleBean();
bean.setId("100");
bean.setName("SomeName");
bean.setCity("SomeCity");
bean.setPhone("1234567890");
return bean;
}
La sortie montre selon l'annotation de l'ordre de la propriété Json:
{
name: "SomeName",
phone: "1234567890",
city: "SomeCity",
id: 100
}
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()) {
Vous pouvez utiliser le code suivant pour effectuer une sérialisation ORDERED et une désérialisation personnalisées du tableau JSON (cet exemple suppose que vous commandez des chaînes, mais que vous pouvez l'appliquer à tous les types):
Sérialisation
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);
Désérialisation
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);
}
}
}
}
au lieu d'utiliser jsonObject, essayez d'utiliser CsvSchema plus facilement et convertit directement l'objet en csv
CsvSchema schema = csvMapper.schemaFor(MyClass.class).withHeader();
csvMapper.writer(schema).writeValueAsString(myClassList);
et il mentionne l'identifiant de commande de votre pojo qui contient @JsonPropertyOrder
Le moyen le plus sûr est probablement de remplacer la méthode des clés utilisée pour générer une sortie:
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();
}
};
Votre exemple:
{
"items":
[
{
"WR":"qwe",
"QU":"asd",
"QA":"end",
"WO":"hasd",
"NO":"qwer"
},
...
]
}
ajouter un élément "itemorder"
{
"items":
[
{
"WR":"qwe",
"QU":"asd",
"QA":"end",
"WO":"hasd",
"NO":"qwer"
},
...
],
"itemorder":["WR","QU","QA","WO","NO"]
}
Ce code génère la sortie souhaitée sans la ligne de titre de colonne:
JSONObject output = new JSONObject(json);
JSONArray docs = output.getJSONArray("data");
JSONArray names = output.getJSONArray("itemOrder");
String csv = CDL.toString(names,docs);