Analyse de JSON à l'aide de l'analyseur JSON
Cette section fournit un bref aperçu du JsonParser, en montrant comment il peut être utilisé pour analyser les détails d'un séisme à partir du fil JSON du United States Geological Survey (USGS), disponible à l'adresse suivante:
earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson.
Comme pour l'analyse XML dans les sections précédentes, les instructions détaillées pour l'analyse JSON sortent du cadre de ce manuel. Cependant, avec de nombreuses API fournissant maintenant des flux JSON, il est important d’introduire les concepts. Comme l’analyseur Pull, l’analyseur JSON vous permet d’analyser un document en une seule passe, en présentant les éléments de votre document dans une série séquentielle d’objets, de tableaux et de valeurs. Pour créer un analyseur récursif, vous devez d'abord créer une méthode de point d'entrée qui utilise un flux d'entrée et crée un nouveau lecteur JSON:
// Create a new Json Reader to parse the input.
// TODO: Parse the InputStream
}
private List<Earthquake> parseJson(InputStream in) throws IOException {
// Create a new Json Reader to parse the input.
JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
// TODO: Parse the InputStream
}
Les données au sein de chaque flux JSON sont stockées sous forme de noms et de valeurs, structurées à l'aide d'objets et de tableaux. Les objets JSON sont utilisés de la même manière que les objets de code, regroupant des valeurs sémantiquement liées. JSON prend également en charge les tableaux pour regrouper plusieurs valeurs ou objets. Par exemple, le fil USGS contient une valeur de type, ainsi que des objets de métadonnées et de cadres de sélection au niveau racine, ainsi qu'un tableau de plusieurs objets de caractéristiques représentant chaque séisme. Chaque objet caractéristique contient ensuite des valeurs pour le type et l'ID, ainsi que des objets permettant de regrouper les propriétés sismiques et les détails géométriques. L'objet géométrie inclut à son tour une valeur pour le type de géométrie et un tableau de valeurs représentant la latitude, la longitude et la profondeur de chaque séisme. Cette structure est illustrée en partie à la figure 7-2. Pour analyser ces structures, créez des méthodes de gestionnaire qui analyseront chaque objet et tableau dans le texte JSON..Pour les méthodes de gestionnaire de structure d’objet, commencez par appeler la méthode beginObject de votre objet JSON Reader pour utiliser l’accolade d’ouverture. Utilisez ensuite la méthode hasNext pour contrôler une boucle while au sein de laquelle vous pouvez extraire des valeurs ou d’autres objets (ou tableaux). Utilisez la méthode endObject pour lire l’accolade de fermeture de l’objet lorsque celui-ci a été entièrement lu:
private MyObject readMyObject
(JsonReader reader
) throws IOException { // Create variables for the return values.
// Consume the opening brace.
reader.beginObject();
// Traverse the values, objects, and arrays within this object.
while (reader.hasNext()) {
// Find the next name.
String name
= reader.
nextName(); // Extract each of the values based on name matches.
if (name.equals("my_value")) {
myValue = reader.nextString();
// Skip any unexpected (or purposefully ignored) values.
} else {
reader.skipValue();
}
}
// Consume closing brace.
reader.endObject();
// Return parsed object.
return new MyObject(myValue);
}
private MyObject readMyObject(JsonReader reader) throws IOException {
// Create variables for the return values.
String myValue = null;
// Consume the opening brace.
reader.beginObject();
// Traverse the values, objects, and arrays within this object.
while (reader.hasNext()) {
// Find the next name.
String name = reader.nextName();
// Extract each of the values based on name matches.
if (name.equals("my_value")) {
myValue = reader.nextString();
// Skip any unexpected (or purposefully ignored) values.
} else {
reader.skipValue();
}
}
// Consume closing brace.
reader.endObject();
// Return parsed object.
return new MyObject(myValue);
}
Les tableaux sont gérés de la même manière, en utilisant les méthodes beginArray et endArray pour consommer respectivement les crochets d’ouverture et de fermeture. Les valeurs dans un tableau sont homogènes, vous permettant d’ajouter simplement chaque valeur à une liste:
public List<Double> readDoublesArray(JsonReader reader)
List<Double> doubles = new ArrayList<Double>();
reader.beginArray();
while (reader.hasNext()) {
doubles.add(reader.nextDouble());
}
reader.endArray();
return doubles;
}
public List<Double> readDoublesArray(JsonReader reader)
throws IOException {
List<Double> doubles = new ArrayList<Double>();
reader.beginArray();
while (reader.hasNext()) {
doubles.add(reader.nextDouble());
}
reader.endArray();
return doubles;
}
Lorsque vous parcourez chaque objet ou tableau, si un objet ou un tableau imbriqué est trouvé, passez simplement l'objet JSON Reader à la méthode d'analyse correspondante. Si un nom inconnu est rencontré, vous pouvez appeler skipValue pour ignorer de manière récursive les jetons imbriqués de la valeur. Le Listing 7-5 montre comment utiliser l'analyseur JSON pour extraire des détails du flux JSON de séisme de magnitude 2,5+ du dernier jour fourni par l'USGS.
LISTING 7-5: Analyse de JSON à l'aide de l'analyseur JSON
// Create a new Json Reader to parse the input.
try {
// Create an empty list of earthquakes.
List<Earthquake> earthquakes = null;
// The root node of the Earthquake JSON feed is an object that
// we must parse.
reader.beginObject();
while (reader.hasNext()) {
String name
= reader.
nextName(); // We are only interested in one sub-object: the array of
// earthquakes labeled as features.
if (name.equals("features")) {
earthquakes = readEarthquakeArray(reader);
} else {
// We will ignore all other root level values and objects.
reader.skipValue();
}
}
reader.endObject();
return earthquakes;
} finally {
reader.close();
}
}
// Traverse the array of earthquakes.
private List<Earthquake> readEarthquakeArray(JsonReader reader)
List<Earthquake> earthquakes = new ArrayList<Earthquake>();
// The earthquake details are stored in an array.
reader.beginArray(); while (reader.hasNext()) {
// Traverse the array, parsing each earthquake.
earthquakes.add(readEarthquake(reader));
}
reader.endArray();
return earthquakes;
}
// Parse each earthquake object within the earthquake array.
public Earthquake readEarthquake
(JsonReader reader
) throws IOException { Location location = null;
Earthquake earthquakeProperties = null;
reader.beginObject();
while (reader.hasNext()) {
String name
= reader.
nextName(); if (name.equals("id")) {
// The ID is stored as a value.
id = reader.nextString();
} else if (name.equals("geometry")) {
// The location is stored as a geometry object
// that must be parsed.
location = readLocation(reader);
} else if (name.equals("properties")) {
// Most of the earthquake details are stored as a
// properties object that must be parsed.
earthquakeProperties = readEarthquakeProperties(reader);
} else {
reader.skipValue();
}
} reader.endObject();
// Construct a new Earthquake based on the parsed details.
return new Earthquake(id, earthquakeProperties.getDate(), earthquakeProperties.getDetails(),location,earthquakeProperties.getMagnitude(),earthquakeProperties.getLink());
}
// Parse the properties object for each earthquake object
// within the earthquake array.
public Earthquake readEarthquakeProperties
(JsonReader reader
) throws IOException { String details
= null; double magnitude
= -1; String link
= null; reader.beginObject(); while (reader.hasNext()) {
String name
= reader.
nextName(); if (name.equals("time")) {
long time = reader.nextLong();
} else if (name.equals("place")) {
details = reader.nextString();
} else if (name.equals("url")) {
link = reader.nextString();
} else if (name.equals("mag")) {
magnitude = reader.nextDouble();
} else {
reader.skipValue();
}
}
reader.endObject();
return new Earthquake(null, date, details, null, magnitude, link);
}
// Parse the coordinates object to obtain a location.
private Location readLocation
(JsonReader reader
) throws IOException { Location location = null;
reader.beginObject();
while (reader.hasNext()) {
String name
= reader.
nextName(); if (name.equals("coordinates")) {
// The location coordinates are stored within an
// array of doubles.
List<Double> coords = readDoublesArray(reader);
location = new Location("dummy");
location.setLatitude(coords.get(0));
location.setLongitude(coords.get(1));
} else {
reader.skipValue();
}
}
reader.endObject();
return location;
}
// Parse an array of doubles.
public List
<Double
> readDoublesArray
(JsonReader reader
) throws IOException { List<Double> doubles = new ArrayList<Double>();
reader.beginArray();
while (reader.hasNext()) {
doubles.add(reader.nextDouble());
}
reader.endArray();
return doubles;
}
private List<Earthquake> parseJson(InputStream in)
throws IOException {
// Create a new Json Reader to parse the input.
JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
try {
// Create an empty list of earthquakes.
List<Earthquake> earthquakes = null;
// The root node of the Earthquake JSON feed is an object that
// we must parse.
reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
// We are only interested in one sub-object: the array of
// earthquakes labeled as features.
if (name.equals("features")) {
earthquakes = readEarthquakeArray(reader);
} else {
// We will ignore all other root level values and objects.
reader.skipValue();
}
}
reader.endObject();
return earthquakes;
} finally {
reader.close();
}
}
// Traverse the array of earthquakes.
private List<Earthquake> readEarthquakeArray(JsonReader reader)
throws IOException {
List<Earthquake> earthquakes = new ArrayList<Earthquake>();
// The earthquake details are stored in an array.
reader.beginArray(); while (reader.hasNext()) {
// Traverse the array, parsing each earthquake.
earthquakes.add(readEarthquake(reader));
}
reader.endArray();
return earthquakes;
}
// Parse each earthquake object within the earthquake array.
public Earthquake readEarthquake(JsonReader reader) throws IOException {
String id = null;
Location location = null;
Earthquake earthquakeProperties = null;
reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
if (name.equals("id")) {
// The ID is stored as a value.
id = reader.nextString();
} else if (name.equals("geometry")) {
// The location is stored as a geometry object
// that must be parsed.
location = readLocation(reader);
} else if (name.equals("properties")) {
// Most of the earthquake details are stored as a
// properties object that must be parsed.
earthquakeProperties = readEarthquakeProperties(reader);
} else {
reader.skipValue();
}
} reader.endObject();
// Construct a new Earthquake based on the parsed details.
return new Earthquake(id, earthquakeProperties.getDate(), earthquakeProperties.getDetails(),location,earthquakeProperties.getMagnitude(),earthquakeProperties.getLink());
}
// Parse the properties object for each earthquake object
// within the earthquake array.
public Earthquake readEarthquakeProperties(JsonReader reader) throws IOException {
Date date = null;
String details = null; double magnitude = -1; String link = null;
reader.beginObject(); while (reader.hasNext()) {
String name = reader.nextName();
if (name.equals("time")) {
long time = reader.nextLong();
date = new Date(time);
} else if (name.equals("place")) {
details = reader.nextString();
} else if (name.equals("url")) {
link = reader.nextString();
} else if (name.equals("mag")) {
magnitude = reader.nextDouble();
} else {
reader.skipValue();
}
}
reader.endObject();
return new Earthquake(null, date, details, null, magnitude, link);
}
// Parse the coordinates object to obtain a location.
private Location readLocation(JsonReader reader) throws IOException {
Location location = null;
reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
if (name.equals("coordinates")) {
// The location coordinates are stored within an
// array of doubles.
List<Double> coords = readDoublesArray(reader);
location = new Location("dummy");
location.setLatitude(coords.get(0));
location.setLongitude(coords.get(1));
} else {
reader.skipValue();
}
}
reader.endObject();
return location;
}
// Parse an array of doubles.
public List<Double> readDoublesArray(JsonReader reader) throws IOException {
List<Double> doubles = new ArrayList<Double>();
reader.beginArray();
while (reader.hasNext()) {
doubles.add(reader.nextDouble());
}
reader.endArray();
return doubles;
}