Essayer de convertir un fichier CSV en JSON
Voici deux exemples de lignes:
-21.3214077;55.4851413;Ruizia cordata
-21.3213078;55.4849803;Cossinia pinnata
J'aimerais avoir quelque chose comme:
"occurrences": [
{
"position": [-21.3214077, 55.4851413],
"taxo": {
"espece": "Ruizia cordata"
},
...
}]
Voici mon script:
echo '"occurences": [ '
cat se.csv | while read -r line
do
IFS=';' read -r -a array <<< $line;
echo -n -e '{ "position": [' ${array[0]}
echo -n -e ',' ${array[1]} ']'
echo -e ', "taxo": {"espece":"' ${array[2]} '"'
done
echo "]";
J'obtiens des résultats vraiment étranges:
"occurences": [
""position": [ -21.3214077, 55.4851413 ], "taxo": {"espece":" Ruizia cordata
""position": [ -21.3213078, 55.4849803 ], "taxo": {"espece":" Cossinia pinnata
Quel est le problème avec mon code?
Le bon outil pour ce travail est jq
.
jq -Rsn '
{"occurrences":
[inputs
| . / "\n"
| (.[] | select(length > 0) | . / ";") as $input
| {"position": [$input[0], $input[1]], "taxo": {"espece": $input[2]}}]}
' <se.csv
émet, compte tenu de votre entrée:
{
"occurences": [
{
"position": [
"-21.3214077",
"55.4851413"
],
"taxo": {
"espece": "Ruizia cordata"
}
},
{
"position": [
"-21.3213078",
"55.4849803"
],
"taxo": {
"espece": "Cossinia pinnata"
}
}
]
}
À propos, une version moins boguée de votre script original pourrait ressembler à ceci:
#!/usr/bin/env bash
items=( )
while IFS=';' read -r lat long pos _; do
printf -v item '{ "position": [%s, %s], "taxo": {"espece": "%s"}}' "$lat" "$long" "$pos"
items+=( "$item" )
done <se.csv
IFS=','
printf '{"occurrences": [%s]}\n' "${items[*]}"
Remarque:
cat
pour insérer une boucle (et de bonnes raisons de ne pas ); ainsi, nous utilisons une redirection (<
) pour ouvrir le fichier directement en tant que stdin de la boucle.read
peut recevoir une liste de variables de destination; il n'y a donc pas besoin de lire dans un tableau (ou first pour lire dans une chaîne, puis de générer un heresting et d'en lire un dans un tableau). Le _
à la fin garantit que les colonnes supplémentaires sont supprimées (en les plaçant dans la variable factice nommée _
) plutôt que ajoutées à pos
."${array[*]}"
génère une chaîne en concaténant des éléments de array
avec le caractère dans IFS
; nous pouvons donc l'utiliser pour nous assurer que les virgules ne sont présentes dans la sortie que lorsqu'elles sont nécessaires.printf
est utilisé de préférence à echo
, comme indiqué dans la section UTILISATION D'APPLICATION de la spécification de echo
elle-même .Voici un article sur le sujet: https://infiniteundo.com/post/99336704013/convert-csv-to-json-with-jq
Il utilise également JQ, mais une approche légèrement différente utilisant split()
et map()
.
jq --Slurp --raw-input \
'split("\n") | .[1:] | map(split(";")) |
map({
"position": [.[0], .[1]],
"taxo": {
"espece": .[2]
}
})' \
input.csv > output.json
Cependant, il ne gère pas l'échappement du séparateur.
En général, si votre jq a le filtre intégré inputs
(disponible depuis jq 1.5), il est préférable de l’utiliser plutôt que l’option de ligne de commande -s.
Ici, dans tous les cas, une solution utilisant inputs
. Cette solution est également sans variable.
{"occurrences":
[inputs
| select(length > 0)
| . / ";"
| {"position": [.[0], .[1]],
"taxo": {"espece": .[2]}} ]}
Ce qui précède suppose bien sûr que le fichier comporte des champs séparés par des points-virgules dans chaque ligne et qu’il n’ya aucune des complications associées aux fichiers CSV.
Si l'entrée comporte des champs strictement délimités par un seul caractère, jq ne devrait pas rencontrer de problèmes pour le gérer. Sinon, il peut être préférable d’utiliser un outil capable de convertir de manière fiable le format TSV (valeur séparée par des tabulations), que jq peut gérer directement.
Étant donné que la solution jq
ne gère pas les échappements CSV, les noms de colonne de la première ligne, les lignes de commentaire et les autres "fonctionnalités" CSV courantes, j'ai étendu l'outil CSV Cruncher pour autoriser la lecture de CSV et son écriture au format JSON. Ce n'est pas exactement "Bash", mais jq
non plus :)
Il s'agit principalement d'une application de traitement CSV en tant que SQL. Ce n'est donc pas complètement trivial, mais voici le truc:
./crunch -in myfile.csv -out output.csv --json -sql 'SELECT * FROM myfile'
Il permet également la sortie sous forme d'objet JSON par ligne ou de tableau JSON approprié. Voir la documentation.
Il est en version bêta, donc tous les commentaires ou demandes d’extraction sont les bienvenus.