json — n_pbt_json #
← Référence des composants · Sommaire du guide
Construire un JSON type par type — texte, nombre, booléen, tableau, objet imbriqué — avec l'échappement fait pour vous, puis en relire un le long d'un chemin :
of_load,of_get_string,of_type,of_count. Un seul objet bâtit vos requêtes et lit vos réponses. Tout en PowerScript pur : aucune page, aucun moteur, PowerBuilder 10 compris.
▶ Le voir en vrai — Application de démonstration, tuile JSON : les résultats, le code qui les produit et cette page, côte à côte.
En bref #
n_pbt_json est autoinstantiate : on le déclare en variable locale, sans create ni destroy. C'est le même objet qui sert, en interne, à bâtir les charges utiles envoyées au moteur — désormais offert à votre code, côté construction et lecture.
Démarrage rapide #
Bâtir une charge utile, puis relire une réponse — tout tient dans une variable locale :
// Local variables
n_pbt_json lnv_json
string ls_customer
double ld_total
// Write : each member is typed and escaped for you - a path may have levels
lnv_json.of_set_string(/*path*/ "customer", /*value*/ "Ada")
lnv_json.of_set_number(/*path*/ "total", /*value*/ 690.50)
lnv_json.of_set_boolean(/*path*/ "paid", /*value*/ true)
// lnv_json.of_text() -> {"customer":"Ada","total":690.5,"paid":true}
// Read : load a response, reach values by path
lnv_json.of_load(/*json*/ '{"order":{"customer":"Ada","total":690.50}}')
IF lnv_json.of_is_valid() THEN
ls_customer = lnv_json.of_get_string(/*path*/ "order/customer") // Ada
ld_total = lnv_json.of_get_number(/*path*/ "order/total") // 690.5
END IF
Un chemin est la suite des clés depuis la racine, jointes par / ; l'index d'un tableau est sa position, comptée à partir de 1, comme toute position de la bibliothèque : order/lines/1 est la première ligne, order/lines/0 ne désigne rien — une écriture le refuse par -5. Un niveau s'écrit comme l'écrit JSON Pointer (RFC 6901) : ~1 est un / de la clé et ~0 un ~ (paths/~1users lit la clé /users ; of_escape_key convertit une clé), un niveau vide est la clé "" (a//b), et un chemin peut commencer par / — la forme complète du pointeur, seule façon de nommer la clé "" de la racine (/). Si un objet écrit la même clé deux fois, c'est sa PREMIÈRE occurrence qui est lue et écrite — un navigateur, lui, retient la dernière.
Construire une charge utile #
| Méthode | Rôle |
|---|---|
of_add_string (string as_path, string as_value) → long | Ajoute une CHAÎNE, échappée pour vous, au TABLEAU situé à as_path. Le tableau doit exister : ouvrez-le d'abord avec of_set_raw et un tableau vide. Rend 0, -4 si as_path est absent ou n'est pas un tableau, -5 si un niveau de as_path est un index 0 sur un tableau ; une chaîne nulle s'écrit vide (pour un null JSON : of_add_raw(as_path, "null")) |
of_add_boolean (string as_path, boolean ab_value) → long | Ajoute un BOOLÉEN (true ou false, jamais entre guillemets) au TABLEAU situé à as_path. Le tableau doit exister : ouvrez-le d'abord avec of_set_raw et un tableau vide. Rend 0, -4 si as_path est absent ou n'est pas un tableau, -5 si un niveau de as_path est un index 0 sur un tableau; une valeur nulle écrit null |
of_add_number (string as_path, long al_value) → long | Ajoute un NOMBRE (cinq surcharges : integer, long, longlong, decimal, double — un decimal et un longlong gardent TOUS leurs chiffres (les centimes d'un montant, le dernier chiffre d'un identifiant au-delà de 2^53), et un littéral comme 690.50 est un decimal, écrit 690.5) au TABLEAU situé à as_path. Le tableau doit exister : ouvrez-le d'abord avec of_set_raw et un tableau vide. Rend 0, -4 si as_path est absent ou n'est pas un tableau, -5 si un niveau de as_path est un index 0 sur un tableau; une valeur nulle écrit null |
of_add_raw (string as_path, string as_json) → long | Ajoute une valeur DÉJÀ en JSON (un objet, un tableau) dont vous répondez au TABLEAU situé à as_path. Le tableau doit exister : ouvrez-le d'abord avec of_set_raw et un tableau vide. Rend 0, -4 si as_path est absent ou n'est pas un tableau, -5 si un niveau de as_path est un index 0 sur un tableau; une valeur nulle ou vide écrit null. Le chemin vide est la RACINE : of_load("[]") puis of_add_raw("", …) bâtit un document qui est un tableau (le corps d'un appel d'API groupé). Ajouter beaucoup d'éléments d'affilée au même tableau reste rapide |
of_set_array (string as_path, string as_values[]) → long | ÉCRIT un TABLEAU entier de chaînes à as_path depuis un tableau PowerBuilder, chaque élément échappé. Un tableau vide en écrit un vide, un élément nul une chaîne vide. Même règle de chemin et mêmes codes que of_set_string |
of_set_members (string as_fragment) → long | Fusionne à la RACINE des membres déjà formés ailleurs, joints par des virgules. Une clé que la racine porte déjà voit sa valeur remplacée sur place, une nouvelle est ajoutée à la fin, une clé que le fragment répète garde sa dernière valeur. Un fragment vide n'écrit rien. Rend 0, -4 si la racine du document n'est pas un objet |
of_clear ( ) → long | Vide le document pour recommencer un autre objet avec la même variable. Rend 0 |
of_text ( ) → string | Le document tel quel (compact) : ce que vous avez bâti (of_add_string, of_add_number...) ou chargé (of_load), après toute modification — la sortie unique, prête à envoyer, stocker ou réécrire. of_pretty en donne la forme indentée. {} si vide ; l'appeler ne vide rien |
Lire un document #
| Méthode | Rôle |
|---|---|
of_load (string as_json) → long | Charge un texte JSON pour la lecture. Rend 0 s'il est bien formé, -5 si l'argument est vide ou blanc (espaces, tabulations, fins de ligne), -4 s'il n'est pas du JSON valide ou imbrique plus de 512 niveaux (le document est alors abandonné). Analyse en PowerScript pur. Un BOM (U+FEFF) en tête, celui d'un fichier enregistré en UTF-8 avec BOM, est ignoré. Sur un code négatif, of_get_last_error dit où le texte est faux (ligne, colonne) et of_error_position à quel caractère. Un document peut n'être qu'une valeur ("abc", 42, null) : elle se lit au chemin vide, rien ne s'y écrit |
of_is_valid ( ) → boolean | Vrai quand l'objet tient un document : le dernier of_load a réussi, ou quelque chose a été écrit depuis. Une valeur passée à of_set_raw / of_add_raw n'est pas revérifiée |
of_exists (string as_path) → boolean | Vrai quand une valeur existe au chemin donné — distingue une valeur présente mais vide d'une valeur absente |
of_type (string as_path) → string | Le type JSON au chemin : object, array, string, number, boolean, null ; vide si absent |
of_get_string (string as_path) → string | La valeur au chemin, en texte : une chaîne décodée, un nombre/booléen/null en texte, un objet ou tableau en JSON brut (rechargeable par of_load) ; une clé écrite deux fois est lue à sa PREMIÈRE occurrence |
of_get_number (string as_path) → double | Le nombre au chemin, en double — le point décimal est honoré sur toute machine (2.5 vaut 2,5, pas 2). 0 si absent; l'exposant est résolu (1e-7, 2.5E+3) et 17 chiffres significatifs sont gardés, zéros de tête de l'exposant compris. Pour un montant ou un identifiant qui doit garder tous ses chiffres : of_get_decimal ou of_get_longlong. Une chaîne ne compte que si elle est tout entière un nombre JSON : "12.50" vaut 12,5, "12 kg" et "1,5" valent 0 |
of_get_decimal (string as_path) → decimal | Le nombre au chemin, en decimal, rebâti depuis le TEXTE du nombre et jamais par un double : 12345678901234.56 revient avec ses centimes, 2.5E-3 vaut 0.0025. 28 chiffres significatifs au plus. 0 si absent, si la valeur n'est pas un nombre, ou au-delà de ce que tient un decimal ; une chaîne ne compte que si elle est tout entière un nombre ("12.50") |
of_get_longlong (string as_path) → longlong | Le nombre au chemin, en entier 64 bits, rebâti depuis son texte et jamais par un double : un identifiant de base comme 9007199254740993 revient entier. Les décimales sont coupées (2.9 donne 2). 0 si absent, si la valeur n'est pas un nombre, ou hors de la plage d'un longlong ; une chaîne ne compte que si elle est tout entière un nombre ("12.50") |
of_get_boolean (string as_path) → boolean | Le booléen au chemin : vrai pour le littéral JSON true et pour la chaîne "true" qu'écrivent certaines API ; faux pour tout le reste |
of_count (string as_path) → long | Le nombre de membres de l'objet, ou d'éléments du tableau, au chemin. Rend -1 si la valeur est scalaire ou absente (distingue un tableau vide, 0, d'un absent, -1). Avec of_name, on parcourt un objet ; un tableau se parcourt par son index dans le chemin (rows/1, rows/2…). Appelé à chaque tour d'une boucle, il ne coûte plus rien une fois le tableau compté, retraits compris |
of_name (string as_path, long al_index) → string | Le nom du membre n° al_index (à partir de 1) de l'objet au chemin — pour lire les clés d'un objet dont on ignore la forme. Avec of_count, on parcourt l'objet. Pour en faire un niveau de chemin : of_escape_key (une clé peut contenir un /) |
of_escape_key (string as_key) → string | Une CLÉ écrite comme UN niveau de chemin (JSON Pointer, RFC 6901) : un ~ devient ~0, puis un / devient ~1 — la clé application/json est le niveau application~1json. Ce qu'il faut à une clé lue par of_name avant de l'insérer dans un chemin |
of_get_array (string as_path, ref string as_values[]) → long | Tous les éléments du tableau au chemin, dans l'ordre, dans as_values (vidé d'abord) — chacun comme of_get_string le lit : une chaîne décodée, un nombre ou un booléen en texte, null en "", un objet ou un tableau en JSON brut (à recharger par of_load dans un autre n_pbt_json). "" désigne la racine. Rend le nombre d'éléments (0 pour un tableau vide), -4 quand il n'y a pas de tableau à ce chemin (rien, un objet, un scalaire), -5 quand un niveau du chemin est un index 0 sur un tableau |
of_pretty ( ) → string | Le document — chargé ou bâti — ré-indenté pour la lecture (plusieurs lignes, tabulations) — un log, une zone de texte. Vide s'il n'y en a pas, ou si une valeur posée par of_set_raw imbrique plus de 512 niveaux (le texte ne serait pas le document) |
of_pretty (long al_indent) → string | Le document — chargé ou bâti — ré-indenté avec al_indent espaces par niveau (2 et 4 sont les largeurs usuelles). 0 l'écrit compact, sur une ligne et sans espace : le plus petit texte à stocker ou à envoyer. Vide s'il n'y a pas de document, ou si al_indent est négatif, supérieur à 16 ou null, ou si une valeur posée par of_set_raw imbrique plus de 512 niveaux. of_pretty() sans argument garde les tabulations |
// Local variables
n_pbt_json lnv_json
string ls_tags[]
string ls_compact
long ll_count
// Read every element of an array at once, then store the document on one line
lnv_json.of_load(/*json*/ '{"customer":{"name":"Ada","tags":["vip","b2b"]}}')
ll_count = lnv_json.of_get_array(/*path*/ "customer/tags", /*values*/ ls_tags) // 2 : vip, b2b
// The document on one line, without a space : the smallest text to store
ls_compact = lnv_json.of_pretty(/*indent*/ 0)
Modifier un document #
Le côté écriture change le document chargé sur place, puis of_text en rend le résultat (compact) — ce qu'on réécrit. Les setters remplacent la valeur au chemin, ou ajoutent la dernière clé quand elle manque à un objet parent. Chacun rend 0, -4 quand un niveau du chemin est un scalaire, ou un tableau sans cet index, -5 sur un chemin vide ou un index 0 sur un tableau. Un tableau rencontré en chemin se traverse par un index qui EXISTE (items/1/qty ajoute qty au premier élément) ; seule une clé d'objet est jamais créée. Une valeur null (nombre, booléen, JSON brut vide) s'écrit null. Une boucle d'écritures, d'ajouts de clés ou de retraits dans un gros document (2 000 lignes) reste rapide : chaque appel ne relit que ce qu'il touche.
| Membre | Rôle |
|---|---|
of_set_string (string as_path, string as_value) → long | ÉCRIT une chaîne à as_path, échappée pour vous. Le chemin peut avoir PLUSIEURS niveaux (a/b/c) : les niveaux absents sont créés en OBJETS, et un document VIDE en devient un — écrire, c'est bâtir. Une valeur déjà là est remplacée, où qu'elle soit. Une clé qui contient un / s'écrit ~1 dans le chemin (of_escape_key). Une boucle d'écritures dans un gros document reste rapide. Rend 0, -4 si un niveau du chemin est un scalaire, ou un tableau sans cet index (un tableau se traverse par un index existant : items/1/qty), -5 sur un chemin vide ou un index 0 sur un tableau. Une chaîne nulle s'écrit vide ; pour un null JSON : of_set_raw(as_path, "null") |
of_set_number (string as_path, long al_value) → long | ÉCRIT un NOMBRE à as_path, le point décimal forcé quelle que soit la région. Cinq surcharges : integer, long, longlong, decimal, double — un decimal et un longlong gardent TOUS leurs chiffres (les centimes d'un montant, le dernier chiffre d'un identifiant au-delà de 2^53), et un littéral comme 690.50 est un decimal, écrit 690.5. Même règle de chemin et mêmes codes que of_set_string; une valeur nulle écrit null |
of_set_boolean (string as_path, boolean ab_value) → long | ÉCRIT un BOOLÉEN à as_path : true ou false, jamais entre guillemets. Même règle de chemin et mêmes codes que of_set_string; une valeur nulle écrit null |
of_set_raw (string as_path, string as_json) → long | ÉCRIT à as_path une valeur DÉJÀ en JSON — un objet imbriqué, un tableau, null — telle quelle : vous en répondez. C'est aussi ainsi qu'on OUVRE un tableau avant of_add_*. Même règle de chemin et mêmes codes que of_set_string; une valeur nulle ou vide écrit null |
of_remove (string as_path) → long | Retire la valeur au chemin — un membre d'objet (sa clé et une virgule partent avec) ou un élément de tableau ; le résultat reste valide. Rend 0, -4 si rien n'est là, -5 sur un chemin vide ou un index 0 sur un tableau |
// Local variables
n_pbt_json lnv_json
// Load, edit in place, then read back the ONE document with of_text
lnv_json.of_load(/*json*/ '{"name":"Ada","active":false}')
lnv_json.of_set_string(/*path*/ "name", /*value*/ "Grace") // replace
lnv_json.of_set_boolean(/*path*/ "active", /*value*/ true)
lnv_json.of_set_number(/*path*/ "count", /*value*/ 3) // added : the key was absent
// lnv_json.of_text() -> {"name":"Grace","active":true,"count":3}
Dates #
Une date s'écrit et se lit en ISO 8601 — ce qu'écrivent les API, les navigateurs et Python —, quel que soit le format de date du poste : une date "2026-10-10", une date-heure "2026-10-10T14:30:00" (sa fraction de seconde suit quand elle n'est pas nulle), une heure "14:30:00". Une valeur nulle écrit null.
| Méthode | Rôle |
|---|---|
of_set_date (string as_path, date ad_value) → long | ÉCRIT une date à as_path (yyyy-mm-dd). Même règle de chemin que of_set_string : rend 0, -4 si un niveau du chemin est un scalaire ou un tableau sans cet index, -5 sur un chemin vide ou un index 0 sur un tableau |
of_set_datetime (string as_path, datetime adt_value) → long | ÉCRIT une date-heure (yyyy-mm-ddThh:mm:ss, la fraction de seconde après un point quand elle n'est pas nulle). Aucun fuseau n'est écrit : l'heure est celle donnée. Rend 0, -4 ou -5, comme of_set_date |
of_set_time (string as_path, time at_value) → long | ÉCRIT une heure (hh:mm:ss). Rend 0, -4 ou -5, comme of_set_date |
of_add_date (string as_path, date ad_value) → long | Ajoute une date au TABLEAU situé à as_path. Rend 0, -4 si as_path est absent ou n'est pas un tableau, -5 si un niveau de as_path est un index 0 sur un tableau |
of_add_datetime (string as_path, datetime adt_value) → long | Ajoute une date-heure au TABLEAU situé à as_path. Rend 0, -4 ou -5, comme of_add_date |
of_add_time (string as_path, time at_value) → long | Ajoute une heure au TABLEAU situé à as_path. Rend 0, -4 ou -5, comme of_add_date |
of_get_date (string as_path) → date | La date écrite au chemin ("2026-10-10", ou la date d'une date-heure). 1900-01-01 si la valeur est absente, n'est pas une date ou nomme un jour qui n'existe pas (2026-02-30) ; of_exists et of_type distinguent une valeur absente |
of_get_datetime (string as_path) → datetime | La date-heure écrite au chemin : un T ou une espace entre date et heure, avec ou sans secondes, avec une fraction de seconde, ou une date seule (minuit). Un Z ou un décalage (+02:00) est lu et non appliqué : l'heure est celle écrite — convertissez-la vous-même quand le fuseau compte. 1900-01-01 00:00:00 si absente ou pas une date |
of_get_time (string as_path) → time | L'heure écrite au chemin ("14:30", "14:30:00", "14:30:00.250", ou l'heure d'une date-heure). 00:00:00 si absente, pas une heure, ou une date seule |
// Local variables
n_pbt_json lnv_json
date ld_due
datetime ldt_created
// Write : ISO 8601, whatever the date format of the machine
lnv_json.of_set_date(/*path*/ "due", /*value*/ Date(2026, 10, 31))
lnv_json.of_set_datetime(/*path*/ "created", /*value*/ DateTime(Date(2026, 10, 10), Time(14, 30, 0)))
// Read what an API writes : the Z is read, the hour stays the one written
lnv_json.of_load(/*json*/ '{"due":"2026-10-31","created":"2026-10-10T14:30:00Z"}')
ld_due = lnv_json.of_get_date(/*path*/ "due")
ldt_created = lnv_json.of_get_datetime(/*path*/ "created")
Un DataStore en JSON, et retour #
PowerBuilder n'a ExportJson et ImportJson qu'à partir de la 2017 R2. n_pbt_json le fait dès PowerBuilder 10, typé par les colonnes : une chaîne, un nombre (un decimal garde tous ses chiffres), une date yyyy-mm-dd, une date-heure, une heure, null pour un NULL. Une surcharge prend un datawindow, une autre un datawindowchild.
| Méthode | Rôle |
|---|---|
of_from_datastore (string as_path, datastore ads_source) → long | ÉCRIT les lignes du tampon principal comme un TABLEAU d'objets à as_path : un objet par ligne, un membre par colonne, nommé comme elle. Le chemin vide fait du DOCUMENT ce tableau (le corps d'un appel groupé). Rend le nombre de lignes écrites, -5 si le DataStore n'est pas valide ou n'a pas de colonne, sinon ce que rend of_set_raw |
of_to_datastore (string as_path, datastore ads_target) → long | INSÈRE le TABLEAU d'objets situé à as_path dans un DataStore : une ligne par objet, chaque membre dans la colonne de même nom (casse ignorée), converti au type de la colonne — un nombre depuis un nombre ou une chaîne qui est tout entière un nombre, une date, une date-heure ou une heure depuis un texte ISO, NULL pour un null ou une valeur que la colonne ne peut tenir. Un membre qui ne nomme aucune colonne est ignoré, un élément qui n'est pas un objet ne fait pas de ligne. Les lignes sont NOUVELLES : Update les insère. Rend le nombre de lignes insérées, -5 si le DataStore n'est pas valide ou n'a pas de colonne, -4 s'il n'y a pas de tableau à as_path |
// Local variables
n_pbt_json lnv_json
datastore lds_orders
long ll_rows
string ls_body
// Send : every row of a retrieved DataStore as typed objects - the body of the call
lds_orders = create datastore
lds_orders.DataObject = "d_orders"
lds_orders.SetTransObject(SQLCA)
lds_orders.Retrieve()
ll_rows = lnv_json.of_from_datastore(/*path*/ "orders", /*source*/ lds_orders)
ls_body = lnv_json.of_text()
// Receive : the objects of a response inserted as NEW rows, ready for Update
lds_orders.Reset()
lnv_json.of_load(/*json*/ '{"data":[{"id":7,"customer":"Grace","amount":"19.99","due":"2026-12-24"}]}')
ll_rows = lnv_json.of_to_datastore(/*path*/ "data", /*target*/ lds_orders)
destroy lds_orders
Quand le texte n'est pas du JSON #
| Méthode | Rôle |
|---|---|
of_get_last_error ( ) → string | Pourquoi le dernier appel a rendu un code négatif ; après un of_load refusé, où le texte est faux et pourquoi : line 2, column 6 : ':' expected after a key. Vide après un appel réussi |
of_error_position ( ) → long | Rend la position, comptée à partir de 1 dans le texte donné au dernier of_load (un BOM compris), du caractère où ce texte devient faux — à sélectionner dans un éditeur ; 0 quand le dernier of_load a réussi |
// Local variables
n_pbt_json lnv_json
long ll_rc
string ls_why
long ll_where
// A response with a colon missing on its second line
ll_rc = lnv_json.of_load(/*json*/ '{"id":4152,~r~n "paid" true}')
IF ll_rc < 0 THEN
ls_why = lnv_json.of_get_last_error() // line 2, column 9 : ':' expected after a key
ll_where = lnv_json.of_error_position() // 22
END IF
Portée. JSON s'analyse en PowerScript pur, sans page ni moteur :
n_pbt_jsonreste autoinstantiate et fonctionne partout, PowerBuilder 10 compris. Pour du XML, voyez xml (qui s'appuie sur le moteur) ; pour afficher un JSON en arbre repliable, voyez jsontree.