Dynamisches Array von Pointern/Adressen in einem struct
-
Auch dein geänderter Code ist noch viel zu groß, das hängt auch damit zusammen, dass deine Datenstruktur viel zu redundant ist.
Statt 660 Zeilen tun es auch 70, dafür dann aber fehlerfrei:
- keine globalen Variablen
- für jeden Anwendungsfall eine Funktion
- wenige Hilfsvariablen (steigert Übersichtlichkeit,...)
- mit wenigen Handgriffen erweiterbar (z.B. zum HTML-Reader)
- bei XML arbeitest du mit Tags, d.h. mit Strings und nicht mit Zeichen, deshalb ist deine zeichenweise Verarbeitung prinzipiell untauglich
- struct-Zeiger-Listen sind unübersichtlich, einfache struct-Listen tun es auch
- Rekursion ist die ultimative Wiederverwendung, minimiert Code, ist hier vertretbar (weil die Zahl der Rekursionsstufen absehbar unkritisch ist) aber dafür meist weniger verständlich
...
------------------------------
- free fehlt noch
- Fehlerbehandlung fehlt noch
...In 'print' musst du jetzt nur noch deinen JSON-Konverter einbauen, und fertig.
/* XML-Minireader (c) Wutz@https://www.c-plusplus.net/forum/334128-20 */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/stat.h> /* kein Standard, haben aber die meisten Compiler im Angebot */ typedef struct entry { char key[20]; /* einfache Arrays reichen hier erstmal */ char value[1000]; int i; struct entry *childs; } Entry; void add(Entry *e, /* Wurzel-Element */ const char *key, /* Tagname der aktuellen Stufe */ const char **s /* Quasi-Stringstream als Input */ ) { char t[3]; memset(e, 0, sizeof*e); sprintf(e->key, "%.19s", key); while (1 == sscanf(*s, "%2s", t)) { if (*t == '<'&&t[1] != '/') { char x[20]; sscanf(strchr(*s, '<') + 1, "%19[^ >]", x); *s = strchr(*s, '>') + 1; e->childs = realloc(e->childs, ++e->i*sizeof*e); add(e->childs + e->i - 1, x, s); } else { if(!e->i) sscanf(*s, "%999[^<]", e->value); *s = strchr(*s, '>') + 1; return; } } } void print(const Entry *e, int n) /* eingerückte Ausgabe (3x space) für jede Stufe/Element */ { printf("%*s<%s>%s%s", n * 3, "", e->key, e->value,e->i?"\n":""); { int i; for (i = 0; i < e->i; ++i) print(e->childs+i, n + 1); } printf("%*s</%s>\n", (e->i?3:0)*n,"", e->key); } int main() { Entry e; struct stat t; int x = stat("standard_small.xml", &t); char *s = calloc(1, t.st_size + 1); FILE *f = fopen("standard_small.xml", "rb"); fread(s, t.st_size, 1, f); fclose(f); add(&e, "", &s); /* Aufsammeln aus String und Baumstruktur füllen */ print(&e, 0); /* Baumelemente stufenweise ausgeben auf stdout */ return 0; }
<> <?xml> <site> <regions> <africa> <item> <location>United States</location> <quantity>1</quantity> <name>duteous nine eighteen </name> <payment>Creditcard</payment> <description> <parlist> <listitem> officer embrace such fears distinction attires <text> page rous lady idle authority capt professes stabs monster petition heave humbly removes rescue runs shady peace most piteous worser oak assembly holes patience but malice whoreson mirrors master tenants smocks yielded </text> </listitem> </parlist> </description> <listitem> <text> shepherd noble supposed dotage humble servilius bitch theirs venus dismal wounds gum merely raise red breaks earth god folds closet captain dying reek </text> </listitem> </item> </africa> <shipping>Will ship internationally, See description for charges</shipping> <incategory> <incategory> <incategory> ...
-
Ich danke dir für dein Codebeispiel und das du doch noch detailliertes Feedback abgegeben hast wie ich meinen Code verbessern könnte.
Auch habe ich nicht gewusst das man mit Scanf in dieser Form arbeiten kann und quasi sogar bis zu Zeichengrenzen einlesen kann. Defintiv etwas das ich hätte mit verwenden können.
Etwas Feedback zu deinem Code habe ich aber auch, so gut wie er geschrieben ist, das Resultat ist falsch bzw. machst du es dir zu einfach.
- Die limitierte Datenlänge für Tag und Daten vorprogrammieren Datenverlust, warum nicht dynamisch?
- es fehlt die Behandlung von Attributen: <book name="The Shogun" label="Red">
Deine Lösung findet nur "book" und wirft die wichtigen Attribute komplett raus- Tags die keine Daten enthalten (im Datenbeispiel "<incategory>" Tags) werden einfach als Kind-Elemente angeordnet, obwohl sie auf gleicher Ebene liegen
- Es fehlt ein Stripping der Whitespaces der Daten, es geht dadurch nichts verloren, aber wenn man die Daten zum Beispiel im Browser ausgibt (weil aus einer Datenbank kommend) hätte man ungewollte Textdarstellungen
- eingebette Tags werden ignoriert und schlimmer Daten einfach abgeschnitten sobald ein Tag in einem Tag auftaucht
und das kleinste Übel:
- XML Deklaration wie das Encoding und XML Version werden mit kopiertIch frage mich auch, wie deine Lösung es schaffen will Json Arrays zu bilden? Da fehlt jegliche Logik da du keine Informationen hast wie viele Elemente auf einer Ebene liegen und welche davon SubArrays beschreiben würden - das genannte Problem mit den Ebenen spielt dabei noch hinzu.
Zu meiner Verteidigung:
Meine Lösung ist zwar bei weitem nicht so professionell umgesetzt, aber sie verliert keine Daten und wertet mehr Informationen beim Parsen der Daten aus die später zum beschreiben der Json gebraucht werden würden.Also 70 Zeilen reichen noch nicht aus
Ich gebe aber zu, mir fehlt das Know-How wie ich richtig mit der Standardbibliothek(en) umgehe, zumal ich noch nicht alles verwendet habe.
Noch kurz zum Thema Speicherleaks/Freeing:
Diese sind behoben und die frees sind nun ohne Null Check.
-
Deine Kritik ist reichlich naiv,
- erstens steht im Kommentar, dass Arrays 'erstmal' reichen sollen
- deine 'fehlenden' Attribute sind ohne Erhöhung der Codezeilen einfach aufnehmbar
- Whitespace-Stripping ist nicht XML konform
- der Code hat nur eine Stelle für potentielle Speicherlecks, im Gegensatz zu deinem
- für die Weiterverarbeitung musst du natürlich den Gesamtpfad aufsammeln, aber genau das macht ja 'print'
- du hast den Code nicht verstanden, du hast das Prinzip der Kapselung in Funktionen mit Übergabe des einen zentralen Objektes aus main nicht verstanden, du möchtest lieber >600 Zeilen pflegen statt 70, viel Spaß