Boîte à outils JSON
Source: tutorial/04_json_toolkit See in Playground
Lit un enregistrement par ligne (un mélange de valeurs JSON valides et de texte invalide), sépare les lignes invalides, classe les valides en objets JSON ou en valeurs scalaires (chaînes, nombres, booléens, tableaux), et écrit un petit résumé JSON des décomptes.
Exécution
cd tutorial/04_json_toolkit
melodium run Compo.toml --input_file records.txtAvec le fichier records.txt fourni (une chaîne, un nombre, un booléen, deux objets aux noms non-ASCII comme Saša et Örség, un tableau, et une ligne invalide), l’exemple journalise chaque enregistrement classé et écrit summary.json :
{"invalid":"1","objects":"2","scalars":"4"}Optionnel : ajoutez --api-report et un jeton d’API (MELODIUM_API_TOKEN) pour voir la trace complète de cette exécution sur Cadence.CI .
Fonctionnement
Cet exemple n’utilise aucun modèle : l’analyse et la validation JSON sont toutes des traitements sans état.
Flux de données
Les lignes sont extraites avec split + flatten + trim, lignes vides éliminées.
Séparer les données invalides avant l’analyse
validate vérifie chaque ligne sans l’analyser ; filter répartit le flux en texte valide (accepted) et en données invalides (rejected, journalisées telles quelles) :
isValid: validate()
split: filter<string>()
nonBlank.accepted -> isValid.text
nonBlank.accepted -> split.value
isValid.is_json -> split.select
logInvalid: logInfos(label="invalid")
split.rejected -> logInvalid.messagesAnalyse et extraction
Seul le texte valide atteint toJson, donc l’analyse ne peut jamais échouer ici. Mais toJson retourne malgré tout un Stream<Option<Json>> par construction (il n’a aucun moyen de savoir, rien qu’à partir du type, que chaque entrée est valide), d’où l’usage de unwrapOr pour obtenir un simple Stream<Json> :
parsed: toJson()
asJson: unwrapOr<Json>(default=|null())
split.accepted -> parsed.text,json -> asJson.option,value -> classify.valueVérifier la validité en amont, avec validate, évite d’avoir à gérer un échec d’analyse plus loin dans le graphe : l’Option renvoyée par toJson doit malgré tout être extraite, mais elle est garantie d’être toujours some.
Classer objets et scalaires
isObject classe chaque valeur Json ; un second filter sépare les objets des scalaires (chaînes, nombres, booléens, tableaux : tout ce qui n’est pas un objet JSON). La plupart des traitements de bibliothèque du type « est-ce que ceci satisfait X », isObject inclus, sont conçus pour se brancher directement sur filter.select :
classify: isObject()
partition: filter<Json>()
asJson.value -> partition.value
classify.is_object -> partition.selectConstruction du résumé
Trois totaux (objets, scalaires, lignes invalides) sont calculés avec un petit traitement local, finalCount<T>, utilisé ici à deux types différents (Json et string) dans le même fichier, sans changer une seule ligne de son corps. Ils sont combinés en un seul StringMap, converti en objet JSON avec fromStringMap, sérialisé avec toString<Json>, et écrit dans summary.json :
withObjects: blockEntry(key="objects")
withScalars: blockInsert(key="scalars")
withInvalid: blockInsert(key="invalid")
objTotal.total -> withObjects.value
withObjects.map -> withScalars.base
scalarTotal.total -> withScalars.value
withScalars.map -> withInvalid.base
invalidTotal.total -> withInvalid.value
summaryStream: stream<StringMap>()
summaryJson: fromStringMap()
summaryText: toString<Json>()
write: writeTextLocal(path=output)
logDone: logInfoMessage(label="json", message="summary written")
withInvalid.map -> summaryStream.block,stream -> summaryJson.value,json -> summaryText.value,into -> write.text
write.finished -> logDone.triggerfromStringMap est le moyen direct de construire un objet JSON à partir de données Mélodium : chaque valeur devient une chaîne JSON, ce qui suffit pour un rapport de synthèse. Pour un JSON plus riche, avec des nombres ou des objets imbriqués, mieux vaut le construire avec les fonctions et traitements json/value::from* pris individuellement.
Dépendances
[dependencies]
std = "0.10.3" # flux de base, journalisation, structures de données
fs = "0.10.3" # lecture/écriture de fichiers locaux
json = "0.10.3" # analyse et sérialisation JSON