J'ai le fichier JSON ci-dessous:
{
"data": [
{
"displayName": "First Name",
"rank": 1,
"value": "VALUE"
},
{
"displayName": "Last Name",
"rank": 2,
"value": "VALUE"
},
{
"displayName": "Position",
"rank": 3,
"value": "VALUE"
},
{
"displayName": "Company Name",
"rank": 4,
"value": "VALUE"
},
{
"displayName": "Country",
"rank": 5,
"value": "VALUE"
},
]
}
J'aimerais avoir un fichier CSV dans ce format:
First Name, Last Name, Position, Company Name, Country
VALUE, VALUE, VALUE, VALUE, VALUE, VALUE
Est-ce possible en utilisant uniquement jq
? Je n'ai aucune compétence en programmation.
jq possède un filtre, @csv, pour convertir un tableau en chaîne CSV. Ce filtre prend en compte la plupart des complexités associées au format CSV, à commencer par les virgules intégrées dans les champs. (jq 1.5 a un filtre similaire, @tsv, pour générer des fichiers de valeurs séparées par des tabulations.)
Bien sûr, si les en-têtes et les valeurs sont tous garantis exempts de virgules et de guillemets doubles, il peut ne pas être nécessaire d'utiliser le filtre @csv. Sinon, il serait probablement préférable de l'utiliser.
Par exemple, si le "Nom de l'entreprise" était "Smith, Smith et Smith", et si les autres valeurs étaient comme indiqué ci-dessous, l'appel de jq avec l'option "-r" produirait un CSV valide:
$ jq -r '.data | map(.displayName), map(.value) | @csv' so.json2csv.json
"First Name","Last Name","Position","Company Name","Country"
"John (""Johnnie"")","Doe","Director, Planning and Posterity","Smith, Smith and Smith","Transylvania"
Je préfère faire de chaque enregistrement une ligne dans mon CSV.
jq '.data | map([.displayName, .rank, .value] | join(", ")) | join("\n")'
Étant donné uniquement ce fichier, vous pouvez faire quelque chose comme:
<testfile jq -r '.data | map(.displayName), map(.value) | join(", ")'
L'opérateur .
Sélectionne un champ dans un objet/hachage. Ainsi, nous commençons par .data
, Qui renvoie le tableau avec les données qu'il contient. Nous mappons ensuite le tableau deux fois, en sélectionnant d'abord displayName, puis en sélectionnant la valeur, en nous donnant deux tableaux avec juste les valeurs de ces clés. Pour chaque tableau, nous joignons les éléments avec "," formant deux lignes. L'argument -r
Indique à jq
de ne pas citer les chaînes résultantes.
Si votre fichier réel est plus long (c'est-à-dire qu'il contient des entrées pour plus d'une personne), vous aurez probablement besoin de quelque chose d'un peu plus compliqué.
J'ai trouvé jq
difficile d'envelopper ma tête. Voici quelques rubis:
Ruby -rjson -rcsv -e '
data = JSON.parse(File.read "file.json")
data["data"].collect {|item| [item["displayName"], item["value"]]}
.transpose
.each {|row| puts row.to_csv}
'
First Name,Last Name,Position,Company Name,Country
VALUE,VALUE,VALUE,VALUE,VALUE
L'analyseur JSON Ruby JSON a échangé sur la virgule de fin avant le crochet de fermeture.
Puisque vous avez marqué ce python
et que le nom du fichier json
est x.json
import os, json
with open('x.json') as f:
x = json.load(f)
print '{}{}{}'.format(', '.join(y['displayName'] for y in x['data']), os.linesep,
', '.join(y['value'] for y in x['data']))
First Name, Last Name, Position, Company Name, Country
VALUE, VALUE, VALUE, VALUE, VALUE
Bien que j'ai dû supprimer la dernière virgule dans votre exemple d'entrée pour le faire fonctionner parce que jq
se plaignait d'attendre un autre élément du tableau, ceci:
INPUT | jq -r '[.[][].displayName], [.[][].value]| join(", ")'
... m'a eu ...
First Name, Last Name, Position, Company Name, Country
VALUE, VALUE, VALUE, VALUE, VALUE
Comment cela fonctionne en un mot:
[]
Vide et la notation .dot
..[][].displayName
.[.[][].displayName], [.[][].value]
join(", ")
à joindre en tant qu'entités distinctes.En vérité, faire [.field]
N'est qu'une autre façon de map(.field)
mais c'est un peu plus spécifique en ce qu'il spécifie le niveau de profondeur pour récupérer les données souhaitées.