JSONPath dans Python : analyser des fichiers JSON avec Python

Aujourd’hui, JSON est l’un des formats les plus utilisés pour l’échange de données entre les applications, notamment sur Internet. JSONPath est un langage d’expression permettant la lecture de données spécifiques à partir d’objets JSON. Découvrez avec nous l’implémentation JSONPath développée par Python et ses principales applications, présentées à l’aide d’exemples simples.

JSONPath dans Python : de quoi s’agit-il ?

JSON est un format de fichiers compatible avec de nombreux systèmes, qui simplifie et optimise l’échange de données structurées entre les applications. Les fichiers JSON sont composés de paires clé-valeur (Key-Value Pairs). Les valeurs peuvent correspondre à différents types de données, qu’il s’agisse de valeurs primitives comme d’objets. Ces objets peuvent aussi renfermer leurs propres paires clé-valeur. Le format JSON étant pris en charge par l’immense majorité des systèmes modernes, il peut être utilisé pour l’échange de données entre des applications de n’importe quel type, que ce soit sur ordinateur (localement) ou sur Internet.

Néanmoins, toutes ces applications n’ont pas toujours besoin de l’ensemble des données contenues dans un fichier JSON. Dans ce genre de situations, la solution JSONPath peut donc vous être utile. JSONPath est un langage d’expression permettant la lecture ciblée d’informations spécifiques à partir d’objets JSON. Dans la plupart des langages de programmation, il convient d’importer JSONPath depuis une bibliothèque externe. Comme de telles bibliothèques doivent être implémentées séparément pour chaque langage, ces bibliothèques ou implémentations peuvent être légèrement différentes les unes des autres.

Le module jsonpath-ng dans Python

jsonpath-ng correspond certainement à l’implémentation la plus courante de JSONPath dans Python. Python a également développé d’autres implémentations JSONPath, notamment jsonpath et jsonpath-rw. Celles-ci restant toutefois moins populaires et complètes, cet article se concentre donc exclusivement sur jsonpath-ng.

Installation

Il est très facile d’installer jsonpath-ng en passant par votre shell. Pour ce faire, il vous suffit de renseigner la commande pip install jsonpath-ng.

Note

L’installation s’effectue depuis le gestionnaire de paquets pip, que Python utilise par défaut. Si ce gestionnaire de paquets n’est pas installé sur votre système, alors vous devez commencer par là. Pour de plus amples informations à ce sujet, vous pouvez consulter le site Web de pip.

Syntaxe

JSONPath vous permet d’exécuter des requêtes complexes sur des objets JSON. Le module renferme donc plusieurs méthodes, opérateurs et expressions atomiques qui peuvent vous aider à sélectionner et interroger des données spécifiques. Les deux méthodes principales utilisées par JSONPath sont parse() et find(). Avec parse(), vous pouvez définir des requêtes pour les référencer et les répéter autant que nécessaire par la suite. Avec find(), vous pouvez exécuter lesdites requêtes sur des données JSON, de manière à en extraire des valeurs concrètes. Pour mieux comprendre leur fonctionnement, étudiez l’exemple ci-dessous :

import json
import jsonpath_ng as jp
raw_data = '''
{
    "nom": "John",
    "âge": 30,
    "domicile": "Marseille"
}
'''
json_object = json.loads(raw_data)
name_query = jp.parse("$.nom")
result = name_query.find(json_object)
print(result[0].value) # Résultat : John
Python

Dans l’exemple ci-dessus, les données JSON sous la forme d’une String ont été converties en un objet dictionnaire grâce à l’utilisation de json.loads. Ce format est en effet le plus efficace pour un travail avec Python. Au moment de la création de name_query, la requête "$.nom" a été définie (pour renvoyer la valeur « nom »). Par la suite, elle a été appliquée à l’objet JSON avec find(). Pour finir, le résultat de la requête a été enregistré dans la variable result, avant d’être lu grâce à result[0].value.

Note

Comme le montre l’exemple ci-dessus, il convient également d’intégrer le module Python json de manière à ce que Python puisse lire les données JSON correspondantes à partir d’une String ou d’un fichier JSON. Ces Strings et ces fichiers peuvent être convertis par la suite à l’aide de loads() ou load(), dans un format pouvant être lu par Python.

En plus de renvoyer la valeur demandée, la méthode « find » apporte également d’autres informations contextuelles, par exemple le chemin d’accès permettant de trouver la valeur recherchée. Ces informations sont renvoyées sous la forme d’une liste, la valeur recherchée correspondant à l’index 0. Vous pouvez donc utiliser result[0].value si vous souhaitez afficher la valeur recherchée.

Dans l’exemple ci-dessus, c’est le symbole du dollar (« $ ») qui a été utilisé afin de définir la requête. Il s’agit donc d’une expression atomique qui permet de faire référence à l’objet racine JSON. L’ensemble des opérateurs et des expressions atomiques est répertorié dans le tableau ci-dessous.

Expression/opérateur Signification Exemple Explication
$ Objet racine $.marc.âge Permet d’accéder à la valeur de la clé « âge » de l’objet « marc ».
. Champ d’un objet $.marc Permet d’accéder à « marc », « marc » correspondant à un champ de l’objet racine.
.. Recherche récursive d’un champ (les champs des sous-objets font aussi l’objet d’un examen) $.people..âge Permet de renvoyer toutes les occurrences du champ « âge » dans « people » et ses sous-objets.
[x] Élément dans un tableau $.people[5] Permet d’accéder au sixième élément (correspondant à l’index 5) du tableau « people ».
\* Caractère générique pour un nombre (généralement utilisé en lien avec des boucles for) $.people[\*] Permet d’accéder à un champ dans « people ». En cas de combinaison avec une boucle for, chaque champ serait renvoyé dans l’ordre.

Outre les expressions et les opérateurs, certains filtres vous permettent également de spécifier encore votre recherche. Dans l’implémentation JSONPath développée par Python, ces filtres peuvent être liés à des opérateurs Python. Tous les symboles pouvant être associés à ces filtres sont présentés, à l’aide d’exemples, dans le tableau suivant.

Symbole Signification Exemple Explication
.[?(filter)] Syntaxe générale pour les filtres (les parenthèses ne sont pas obligatoires) $.people[?(@.name == "Anne")] Permet d’accéder aux personnes ayant pour prénom « Anne ».
@ Objet soumis à examen (souvent utilisé dans le contexte d’une boucle for) $.people[?(@.âge < 50)] Permet d’accéder aux champs de « people » dont la valeur présente dans « âge » est inférieure à 50.
<, >, <=, >=, == et != Opérateurs de comparaison (permettant de filtrer certains résultats de recherche) $.people[@.âge < 50 & @.âge > 20] Permet d’accéder aux personnes dont l’âge est compris entre 20 et 50 ans.
& ET logique $.people[?(@.domicile == ’Paris’ & @.âge > 40)] Permet d’accéder aux personnes dont l’âge est supérieur à 40 ans ET qui résident à Paris.
Note

Vous souhaitez utiliser des filtres ? Optez pour le module jsonpath_ng.ext, puis faites-y référence au moment de l’appel de parse().

Exemple d’application pour JSONPath dans Python

import json
import jsonpath_ng as jp
import json
import jsonpath_ng as jp
# JSON-Daten als String
data = """
{
    "villes": [
        {
            "nom": "Paris",
            "région": "Île-de-France",
            "habitants": 2145000,
            "estunecapitale": true,
            "15ième arrondissement": {
                "habitants": 230000    
            }
        },
        {
            "nom": "Marseille",
            "région": "Provence-Alpes-Côte d'Azur",
            "habitants": 873000,
            "estunecapitale": false
        },
        {
            "nom": "Lyon",
            "région": "Rhône-Alpes",
            "habitants": 537000,
            "estunecapitale": false
        },
        {
            "nom": "Lille",
            "région": "Hauts-de-France",
            "habitants": 236000
        }
    ]
}
"""
# Convertir des données de String en object dictionnaire
json_data = json.loads(data)
# Demande : noms de toutes les villes
query1 = jp.parse("villes[*].nom")
for match in query1.find(json_data):
    print(match.value)     # Résultat : Paris, Marseille, Lyon, Lille
# importer jsonpath_ng.ext pour appliquer les filtres
import jsonpath_ng.ext as jpx
# Demande : noms de toutes les villes de moins de 1 million d'habitants
query2 = jpx.parse("$.villes [?@.habitants < 1000000].nom")
for match in query2.find(json_data):
    print(match.value)     # Résultat : Marseille, Lyon, Lille
# Tous les champs avec "habitants"
query3 = jp.parse("$.villes..habitants")
match = query3.find(json_data)
for i in match:
    print(i.value)     # Résultat : 2145000, 230000, 873000, 537000, 236000
# Les noms de toutes les villes qui ne s'appellent pas "Marseille"
query4 = jpx.parse('$.villes[?(@.nom != "Marseille")].nom')
for match in query4.find(json_data):
    print(match.value)     # Résultat : Paris, Lyon, Lille
Python

Dans cet exemple, les données JSON prennent la forme d’une String, avant d’être converties en un objet dictionnaire grâce à loads(). L’objet racine contient uniquement un tableau, renfermant lui-même quatre villes. Pour chaque ville, il existe quatre champs correspondant aux données suivantes :

  • le nom de la ville ;
  • la région dans laquelle elle se trouve ;
  • son nombre d’habitants ;
  • une indication précisant s’il s’agit ou non de la capitale de la France.

La ville de Paris est dotée d’un champ supplémentaire du nom de « 15ième arrondissement », auquel un nombre d’habitants est également associé.

Une fois les données converties dans un format approprié, quatre différentes sont exécutées. Leurs modes de fonctionnement et résultats sont détaillés directement dans l’exemple à l’aide de commentaires. Comme vous l’avez peut-être remarqué, la troisième requête renvoie cinq valeurs différentes ; en effet, l’opérateur .. recherche les champs correspondants de façon récursive. Tous les objets sont ainsi examinés, y compris l’ensemble des « enfants » desdits objets. Ainsi, le nombre d’habitants dans l’arrondissement de Pankow apparaît à côté du nombre d’habitants dans les autres villes.

Conseil

Cette solution alliant JSON à Python constitue un outil polyvalent dans le domaine de la programmation Internet. Vous souhaitez publier rapidement, facilement et directement une application Web en passant par Git ? La méthode Deploy Now proposée par IONOS est parfaite pour vous.