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.
→ std.string · Guide: Daten & Serialisierung · 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. „Holeuser.nameaus diesem JSON„ ist mitstd.jsonnicht möglich;parseValuemeldet bei einem Objekt nur den Typ und lässt den Zielpuffer unberührt (#1435).
* Kein verlustfreier Durchlauf.toArray→stringifymacht aus[1,2,3]das Dokument["1","2","3"]— aus Zahlen werden Zeichenketten (#1432).
* Keine Prüfung des Inhalts von Arrays und Objekten:[abc]gilt als gültig (#1434).
* Keine Steuerzeichen-Maskierung — das Ergebnis vonJSONEscapekann ungültiges JSON sein (#1433).
Für echte Dokumentverarbeitung führt der 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.parseArraygibt einen Fehlercode zurück (0= Erfolg),parseValueeinen Typ,toArray/stringify/JSONEscapeden 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.
JSONEscapemaskiert 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 (#1433).
Umgekehrt versteht die Unit\uXXXXbeim Einlesen nicht — aus einem maskiertenAwirdu0041.
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 (#1432). Vier Dinge gehen schief:
- Zahlen werden zu Zeichenketten:[1,2,3]kommt als["1","2","3"]zurück, weilserializeArrayjedes 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 mitStrSplitaus, statt überstringifyzu gehen.
Die Pipe-Form lässt sich mit StrSplit aus 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 (#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:MuellliefertJSON_NUMBERund landet unverändert im Puffer. Vor der Auswertung also den Typ prüfen und beiJSON_OBJECTden Puffer selbst leeren.
Fallstricke
- Zielpuffer gehören dem Aufrufer und werden nicht auf Größe geprüft. Für
JSONEscapesind zwei Byte je Eingabezeichen plus zwei für die Anführungszeichen sicher. JSONEscapesetzt die Anführungszeichen selbst — wer sie zusätzlich schreibt, bekommt doppelte.isValidJSONist keine Eingangsprüfung für fremde Daten.- Kein Objektzugriff, keine Pfadausdrücke, keine Zahlen-Umwandlung — was aus
parseValuekommt, ist Text; fürint64anschließendStrToIntaus std.string. - Kein Whitespace-Handling zwischen Elementen:
[1, 2]ergibt im Pipe-Format1| 2— mit führendem Leerzeichen im zweiten Element. serializeValuemaskiert nur beiJSON_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: Guide: Daten & Serialisierung · std.string · std.xml · std.net.http · 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 (#1432), JSONEscape maskiert keine Steuerzeichen (#1433), isValidJSON prüft […]/{…} nur auf Klammerpaare (#1434), parseValue lässt dest bei Objekten unberührt (#1435). Geprüft mit lyxc 1.0.21A.
