CSV nach JSON - Mapping Problem

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
heidob
User
Beiträge: 5
Registriert: Mittwoch 3. Juni 2020, 20:18

Hallo.

Dies ist mein erster Post in diesem Forum. Ich bin kein Programmierer, und auch was Python betrifft, sehe ich mich eher als Anfänger.
Mein Problem ist folgendes: Ich habe eine CSV-Datei mit folgendem Inhalt...

Code: Alles auswählen

Nummer;Name;Strasse;PLZ;Ort;Land;email
1;Max Mustermann;Hauptstr. 1;12345;Musterstadt;DE;;
2;Max Musterfrau; Berliner Weg 22;34567;Irgendwo;DE;max@example.org
und brauche diese Daten in folgender JSON-Struktur:

Code: Alles auswählen

{
            "customers" :
            [
                {
                    "customerNumber": "1",
                    "name": "Max Mustermann",
                    "location":
                    {
                        "type": 2,
                        "id": "",
                        "name": "Max Mustermann",
                        "postal": "12345",
                        "city": "Musterstadt",
                        "street": "Hauptstr. 1",
                        "country": "DE"
                    }
                },
                {
                    "customerNumber": "2",
                    "name": "Max Musterfrau",
                    "location":
                    {
                        "type": 2,
                        "id": "",
                        "name": "Max Musterfrau",
                        "postal": "34567",
                        "city": "Irgendwo",
                        "street": "Berliner Weg 22",
                        "country": "DE"
                    }
                }
            ]
}
Mein Problem ist vor allem das Mapping. Ich habe keinen Plan, wie ich das machen muss, oder wo ich ansetzen kann. Ich weiß, dass es die Module 'csv' und 'json' gibt, weiß aber nicht ob/wie ich damit zum Ziel komme.
Wie würdet ihr vorgehen?`

Viele Grüße,
heidob
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Mit dem csv-Modul die Datei einlesen. Dabei gleich in die gewünschte Struktur bringen und diese Struktur anschließend mit dem json-Modul schreiben.
heidob
User
Beiträge: 5
Registriert: Mittwoch 3. Juni 2020, 20:18

Hallo sparrow. Danke für deine Antwort. So hatte ich mir das auch vorgestellt, mit dem csv-Modul lesen und mit dem json-Modul schreiben. Aber dieses "gleich in die gewünschte Struktur bringen" macht mir Probleme. Wie mache ich mir diese Struktur und von welchem Typ könnte die sein (list, dict, string)?

Bislang weiß ich, dass ich so das CSV öffne und dann quasi mit einem Dict arbeite:

Code: Alles auswählen

with open('Mappe1.csv') as csvfile:
    reader = csv.DictReader(csvfile, delimiter=';')
    for row in reader:
        print(row['country'], row['city']
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Quasi geratener Code hilft aber leider nicht weiter.
Mich würde nämlich sehr wundern, wenn row['country'] an der Stelle funktioniert.

Der erste Schritt wäre also erst einmal, die csv-Datei auszulesen. Wie das geht, steht in der umfänglichen Dokumentation.

Und welche Datenstruktur die richtige ist, ergibt sich aus der JSON-Datei. Geschweifte Klammern kennzeichnen ein Dictionary, eckige eine Liste.
heidob
User
Beiträge: 5
Registriert: Mittwoch 3. Juni 2020, 20:18

ja, row['country'] funktioniert nicht, row['Land'] sollte schon funktionieren.
Wenn ich mir das obige JSON ansehe, ist das ein Dict mit einem Key (customers) und einer Liste als Value. Die Einträge in der Liste sind dann wieder Dicts und 'location' ist ein Key mit mehreren Values.
Ich probiere einfach mal weiter...
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@heidob: wenn die Zeilen bei Dir funktionieren, dann ist die Beispieldatei falsch, dort sind die Überschriften in Deutsch.
Wie sieht denn Deine Zielstruktur aus?: jede Zeile in der CSV-Datei entspricht ja einem Wörterbuch in einer Liste, nur dass die Struktur innerhalb des Wörterbuchs anders ist, als das, das Du mit DictReader liest. Du mußt also aus dem gelesenen Wörterbuch ein passendes erzeugen.
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

“postal” macht mir ja ein bisschen Angst. 😉 Sicher dass das nicht „postalCode“ oder „postcode“ heissen sollte‽
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
heidob
User
Beiträge: 5
Registriert: Mittwoch 3. Juni 2020, 20:18

Sirius3 hat geschrieben: Donnerstag 4. Juni 2020, 16:14 @heidob: wenn die Zeilen bei Dir funktionieren, dann ist die Beispieldatei falsch, dort sind die Überschriften in Deutsch.
Wie sieht denn Deine Zielstruktur aus?: jede Zeile in der CSV-Datei entspricht ja einem Wörterbuch in einer Liste, nur dass die Struktur innerhalb des Wörterbuchs anders ist, als das, das Du mit DictReader liest. Du mußt also aus dem gelesenen Wörterbuch ein passendes erzeugen.
Ja, die Überschriften in der CSV sind deutsch, richtig. Wie gesagt, ein row['Land'] würde dann funktionieren. Meine Zielstruktur habe ich oben bereits gepostet (JSON). Meinst du das?
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Für solche Umformungen verwende ich gerne das `glom`-Modul:

Code: Alles auswählen

#!/usr/bin/env python3
import csv
import json

from glom import glom, Literal


def main():
    with open("test2.csv", encoding="utf-8", newline="") as csv_file:
        data = glom(
            csv.DictReader(csv_file, delimiter=";"),
            {
                "customers": [
                    {
                        "customerNumber": ("Nummer", int),
                        "name": "Name",
                        "location": {
                            "type": Literal(2),
                            "id": Literal(""),
                            "postcode": "PLZ",
                            "city": "Ort",
                            "street": "Strasse",
                            "country": "Land",
                        },
                    }
                ]
            },
        )

    with open("test.json", "w", encoding="utf-8") as json_file:
        json.dump(data, json_file, indent=2)


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
heidob
User
Beiträge: 5
Registriert: Mittwoch 3. Juni 2020, 20:18

Ich konnte es jetzt wie folgt lösen:

Code: Alles auswählen

import csv
import json

data = {'customers': []}

with open('Mappe1.csv', encoding='utf-8-sig') as csvfile:
    csvreader = csv.DictReader(csvfile, delimiter=';')
    for row in csvreader:
        data['customers'].append(row)

with open('mytest.json', 'w', encoding='utf-8') as jsonfile:
    jsonfile.write(json.dumps(data, indent=4, ensure_ascii=False))
Vielen Dank an alle, die sich die Zeit genommen haben.
Bye!
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@heidob: Das ist sowohl beim Lesen als auch beim Schreiben ein kleines bisschen umständlicher als es sein müsste.

Beim Lesen kann man sich die Schleife sparen in dem man den Inhalt vom Reader einfach direkt in einer Liste sammelt.

Und beim Schreiben muss man nicht erst eine Zeichenkette erzeugen und die dann schreiben, sondern man kann gleich `json.dump()` verwenden um zu schreiben.

Code: Alles auswählen

#!/usr/bin/env python3
import csv
import json


def main():
    with open("Mappe1.csv", encoding="utf-8-sig") as csv_file:
        data = {"customers": list(csv.DictReader(csv_file, delimiter=";"))}

    with open("test.json", "w", encoding="utf-8") as json_file:
        json.dump(data, json_file, indent=4, ensure_ascii=False)


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten