====== std.json ======
JSON auf Textebene: Sonderzeichen maskieren, Wohlgeformtheit grob prüfen, einen Einzelwert einlesen und **flache Arrays** über ein Pipe-getrenntes Zwischenformat verarbeiten. Ein Dokumentmodell mit Objektzugriff gibt es nicht.
→ [[lyx_-_programmiersprache:units:string|std.string]] · [[lyx_-_programmiersprache:guides:daten-serialisierung|Guide: Daten & Serialisierung]] · [[lyx_-_programmiersprache:units|Standard Library]]
Alle Beispiele dieser Seite sind mit ''lyxc 1.0.21A'' übersetzt und ausgeführt; die gezeigten Ausgaben sind echte Programmausgaben.
**Einsatz:** einfache REST-Antworten auswerten, Zahlenlisten übergeben, Werte für die Ausgabe maskieren.
> **Was diese Unit nicht kann — vor dem ersten Einsatz lesen:**
>
> * **Kein Objektzugriff.** „Hole ''user.name'' aus diesem JSON" ist mit ''std.json'' nicht möglich; ''parseValue'' meldet bei einem Objekt nur den Typ und lässt den Zielpuffer unberührt ([[https://github.com/SEOLizer/LyX-Compiler/issues/1435|#1435]]).
> * **Kein verlustfreier Durchlauf.** ''toArray'' → ''stringify'' macht aus ''%%[1,2,3]%%'' das Dokument ''%%["1","2","3"]%%'' — aus Zahlen werden Zeichenketten ([[https://github.com/SEOLizer/LyX-Compiler/issues/1432|#1432]]).
> * **Keine Prüfung des Inhalts** von Arrays und Objekten: ''%%[abc]%%'' gilt als gültig ([[https://github.com/SEOLizer/LyX-Compiler/issues/1434|#1434]]).
> * **Keine Steuerzeichen-Maskierung** — das Ergebnis von ''JSONEscape'' kann ungültiges JSON sein ([[https://github.com/SEOLizer/LyX-Compiler/issues/1433|#1433]]).
>
> Für echte Dokumentverarbeitung führt der [[lyx_-_programmiersprache:guides:daten-serialisierung|Guide]] die gangbaren Wege auf.
----
===== Typ- und Fehlercodes =====
^ Konstante ^ Wert ^ ^ Konstante ^ Wert ^
| ''JSON_NULL'' | 0 | | ''ERR_JSON_OK'' | 0 |
| ''JSON_BOOL'' | 1 | | ''ERR_JSON_INVALID'' | 1 |
| ''JSON_NUMBER'' | 2 | | ''ERR_JSON_EXPECTED'' | 2 |
| ''JSON_STRING'' | 3 | | ''ERR_JSON_EOF'' | 3 |
| ''JSON_ARRAY'' | 4 | | ''ERR_JSON_ESCAPE'' | 4 |
| ''JSON_OBJECT'' | 5 | | | |
Die ''JSON_*''-Werte liefert ''parseValue'' als **Typ**, die ''ERR_JSON_*''-Werte liefert ''parseArray'' als **Fehlercode**. Von den fünf Fehlercodes verwendet die Unit nur ''ERR_JSON_OK'' und ''ERR_JSON_INVALID''.
> **Rückgabewerte bedeuten je Funktion etwas anderes.** ''parseArray'' gibt einen **Fehlercode** zurück (''0'' = Erfolg), ''parseValue'' einen **Typ**, ''toArray''/''stringify''/''JSONEscape'' den **Zielzeiger**. Das Ergebnis steht in allen Fällen im Zielpuffer, den der Aufrufer stellt.
----
===== Prüfen, einlesen, maskieren =====
^ Signatur ^ Beschreibung ^
| ''isValidJSON(s: pchar): bool'' | Grobprüfung — bei Skalaren genau, bei ''%%[…]%%'' und ''%%{…}%%'' nur die Klammerpaare |
| ''parseValue(dest, src): int64'' | Einzelwert; Rückgabe ist der ''JSON_*''-Typ, der Wert landet in ''dest'' |
| ''parseArray(dest, src): int64'' | JSON-Array ins Pipe-Format; Rückgabe ist ein ''ERR_JSON_*''-Code |
| ''toArray(dest, json_str): pchar'' | wie ''parseArray'', leert ''dest'' im Fehlerfall |
| ''JSONEscape(dest, src): pchar'' | maskiert ''"'', ''\'', Zeilenumbruch, Wagenrücklauf, Tabulator — **und setzt Anführungszeichen** |
| ''serializeValue(dest, value, json_type): pchar'' | maskiert bei ''JSON_STRING'', kopiert sonst unverändert |
| ''serializeArray(dest, src): pchar'' · ''stringify(dest, pipe_str): pchar'' | Pipe-Format zurück nach JSON (identisch) |
import std.json;
import std.alloc;
import std.string;
fn J(b: bool): pchar { if (b) { return "gueltig"; } return "ungueltig"; }
fn main(): int64 {
var d: pchar := alloc(1024) as pchar;
// Pruefen: Skalare werden genau geprueft, Arrays und Objekte nur auf Klammerpaare
PrintLn(StrConcat("'{\"a\":1}' ", J(isValidJSON("{\"a\":1}"c))));
PrintLn(StrConcat("'[1,2,3]' ", J(isValidJSON("[1,2,3]"c))));
PrintLn(StrConcat("'nonsense' ", J(isValidJSON("nonsense"c))));
PrintLn(StrConcat("'12.5' ", J(isValidJSON("12.5"c))));
PrintLn(StrConcat("'12.5.7' ", J(isValidJSON("12.5.7"c))));
PrintLn(StrConcat("'[abc]' ", J(isValidJSON("[abc]"c))));
// Array einlesen: der Rueckgabewert ist ein Fehlercode, das Ergebnis steht in dest
var rc: int64 := parseArray(d, "[1,2,3]"c);
PrintLn(StrConcat(StrConcat("parseArray rc=", IntToStr(rc)), StrConcat(" Pipe-Form: ", d)));
// Einzelwert einlesen: der Rueckgabewert ist der Typ
var typ: int64 := parseValue(d, "\"Hallo\""c);
PrintLn(StrConcat(StrConcat("parseValue Typ=", IntToStr(typ)), StrConcat(" Inhalt: ", d)));
// Maskieren fuer die Ausgabe
JSONEscape(d, "Er sagte \"Hallo\"\nund ging"c);
PrintLn(StrConcat("JSONEscape: ", d));
return 0;
}
'{"a":1}' gueltig
'[1,2,3]' gueltig
'nonsense' ungueltig
'12.5' gueltig
'12.5.7' ungueltig
'[abc]' gueltig
parseArray rc=0 Pipe-Form: 1|2|3
parseValue Typ=3 Inhalt: Hallo
JSONEscape: "Er sagte \"Hallo\"\nund ging"
Die Skalarprüfung ist seit #1269 belastbar: ''nonsense'' und ''12.5.7'' werden abgewiesen, ''true''/''false''/''null'' namentlich verglichen. Nur der **Inhalt** von Arrays und Objekten bleibt ungeprüft — dort zählt allein, ob sich zur öffnenden Klammer eine schließende findet.
> **''JSONEscape'' maskiert keine Steuerzeichen.** Alles unter U+0020 außer Zeilenumbruch, Wagenrücklauf und Tabulator geht roh durch; RFC 8259 verlangt für jedes dieser Zeichen eine ''\u00XX''-Folge. Ein Byte 0x01 aus einer Protokollzeile oder einem Datenbankfeld macht das Ergebnis für strenge Parser unlesbar ([[https://github.com/SEOLizer/LyX-Compiler/issues/1433|#1433]]).
>
> Umgekehrt versteht die Unit ''\uXXXX'' beim Einlesen nicht — aus einem maskierten ''A'' wird ''u0041''.
----
===== Das Pipe-Format =====
Arrays werden nicht als Struktur geführt, sondern als eine Zeichenkette, in der die Elemente durch ''|'' getrennt sind. ''parseArray'' erzeugt sie, ''stringify'' macht daraus wieder JSON.
import std.json;
import std.alloc;
import std.string;
fn Zeig(json: pchar): void {
var pipe: pchar := alloc(1024) as pchar;
var back: pchar := alloc(1024) as pchar;
toArray(pipe, json);
stringify(back, pipe);
PrintLn(StrConcat(StrConcat(json, " -> "), StrConcat(pipe, StrConcat(" -> ", back))));
}
fn main(): int64 {
Zeig("[1,2,3]"c);
Zeig("[\"a\",\"b\"]"c);
Zeig("[1,[2,3]]"c);
Zeig("[\"a|b\",\"c\"]"c);
return 0;
}
[1,2,3] -> 1|2|3 -> ["1","2","3"]
["a","b"] -> "a"|"b" -> ["\"a\"","\"b\""]
[1,[2,3]] -> 1|[2,3] -> ["1","[2,3]"]
["a|b","c"] -> "a|b"|"c" -> ["\"a","b\"","\"c\""]
> **Der Durchlauf ist nicht verlustfrei** ([[https://github.com/SEOLizer/LyX-Compiler/issues/1432|#1432]]). Vier Dinge gehen schief:
>
> - **Zahlen werden zu Zeichenketten**: ''%%[1,2,3]%%'' kommt als ''%%["1","2","3"]%%'' zurück, weil ''serializeArray'' jedes Element in Anführungszeichen setzt.
> - **Zeichenketten werden doppelt maskiert**: die Anführungszeichen stehen im Pipe-Format noch drin.
> - **Verschachtelung wird Text**: aus dem inneren ''%%[2,3]%%'' wird die Zeichenkette ''%%"[2,3]"%%''.
> - **Ein ''|'' im Wert erzeugt zusätzliche Elemente** — aus zwei werden drei.
>
> Brauchbar ist das Format also für **flache Arrays gleichartiger Werte ohne Pipe-Zeichen**. Wer Zahlen zurückbekommen will, liest die Pipe-Form selbst mit ''StrSplit'' aus, statt über ''stringify'' zu gehen.
Die Pipe-Form lässt sich mit ''StrSplit'' aus [[lyx_-_programmiersprache:units:string|std.string]] weiterverarbeiten — das ist der vorgesehene Weg, an die einzelnen Werte zu kommen.
----
===== Einzelwerte =====
''parseValue'' erkennt den Typ am ersten Zeichen und legt den Wert in ''dest'' ab:
^ Eingabe ^ Rückgabe ^ ''dest'' ^
| ''%%"Hallo"%%'' | ''JSON_STRING'' (3) | ''Hallo'' — Anführungszeichen entfernt, Maskierungen aufgelöst |
| ''%%[1,2]%%'' | ''JSON_ARRAY'' (4) | Pipe-Form ''%%1|2%%'' |
| ''%%{"a":1}%%'' | ''JSON_OBJECT'' (5) | **unverändert** — der Puffer wird nicht angefasst |
| ''true'' / ''false'' | ''JSON_BOOL'' (1) | ''true'' / ''false'' |
| ''null'' | ''JSON_NULL'' (0) | ''null'' |
| ''42'', ''3.5'' | ''JSON_NUMBER'' (2) | die Ziffern |
| alles andere | ''JSON_NUMBER'' (2) | die Eingabe unverändert |
> **Zwei Fallen in dieser Tabelle** ([[https://github.com/SEOLizer/LyX-Compiler/issues/1435|#1435]]): Bei einem **Objekt** bleibt der Zielpuffer unberührt — dort steht dann noch, was ein vorheriger Aufruf hinterlassen hat. Und **unbekannte Eingaben werden als Zahl gemeldet**: ''Muell'' liefert ''JSON_NUMBER'' und landet unverändert im Puffer. Vor der Auswertung also den Typ prüfen **und** bei ''JSON_OBJECT'' den Puffer selbst leeren.
----
===== Fallstricke =====
* **Zielpuffer gehören dem Aufrufer** und werden nicht auf Größe geprüft. Für ''JSONEscape'' sind zwei Byte je Eingabezeichen plus zwei für die Anführungszeichen sicher.
* **''JSONEscape'' setzt die Anführungszeichen selbst** — wer sie zusätzlich schreibt, bekommt doppelte.
* **''isValidJSON'' ist keine Eingangsprüfung** für fremde Daten.
* **Kein Objektzugriff, keine Pfadausdrücke, keine Zahlen-Umwandlung** — was aus ''parseValue'' kommt, ist Text; für ''int64'' anschließend ''StrToInt'' aus [[lyx_-_programmiersprache:units:string|std.string]].
* **Kein Whitespace-Handling** zwischen Elementen: ''%%[1, 2]%%'' ergibt im Pipe-Format ''%%1| 2%%'' — mit führendem Leerzeichen im zweiten Element.
* **''serializeValue'' maskiert nur bei ''JSON_STRING''.** Für alle anderen Typen kopiert es die Eingabe wörtlich — auch dann, wenn dort etwas steht, das kein gültiges JSON ist.
----
**Weiterführend:** [[lyx_-_programmiersprache:guides:daten-serialisierung|Guide: Daten & Serialisierung]] · [[lyx_-_programmiersprache:units:string|std.string]] · [[lyx_-_programmiersprache:units:xml|std.xml]] · [[lyx_-_programmiersprache:units:net:http|std.net.http]] · [[lyx_-_programmiersprache:units|Standard Library]]
**Quelle:** ''std/json.lyx'' (480 Zeilen) · **Autor:** Andreas Röne · **Copyright:** 2024–2025 Andreas Röne
Letzte Aktualisierung: 2026-08-13 — Seite gegen ''std/json.lyx'' überarbeitet: zwei lauffähige Beispiele mit echter Ausgabe, Rückgabewert-Bedeutungen je Funktion, Verhaltenstabelle für ''parseValue'', Grenzen des Pipe-Formats, Fallstricke. Belegt und als Issue erfasst: Pipe-Durchlauf verliert Typen ([[https://github.com/SEOLizer/LyX-Compiler/issues/1432|#1432]]), ''JSONEscape'' maskiert keine Steuerzeichen ([[https://github.com/SEOLizer/LyX-Compiler/issues/1433|#1433]]), ''isValidJSON'' prüft ''%%[…]%%''/''%%{…}%%'' nur auf Klammerpaare ([[https://github.com/SEOLizer/LyX-Compiler/issues/1434|#1434]]), ''parseValue'' lässt ''dest'' bei Objekten unberührt ([[https://github.com/SEOLizer/LyX-Compiler/issues/1435|#1435]]). Geprüft mit ''lyxc 1.0.21A''.