PBToolboxAI v5 ← Site

json — n_pbt_json #

← Referencia de componentes · Índice de la guía

Construir un JSON tipo por tipo — texto, número, booleano, arreglo, objeto anidado — con el escapado hecho por usted, y luego leer uno a lo largo de una ruta: of_load, of_get_string, of_type, of_count. Un solo objeto construye sus peticiones y lee sus respuestas. Todo en PowerScript puro: sin página, sin motor, PowerBuilder 10 incluido.

▶ Verlo en vivo — Aplicación de demostración, mosaico JSON: los resultados, el código que los produce y esta página, lado a lado.


En resumen #

n_pbt_json es autoinstantiate: se declara como variable local, sin create ni destroy. Es el mismo objeto que, internamente, construye las cargas útiles enviadas al motor — ahora ofrecido a su código, del lado de construcción y de lectura.

Inicio rápido #

Construir una carga útil y luego releer una respuesta — todo cabe en una variable local:

// 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

Una ruta son las claves desde la raíz unidas por /; el índice de un arreglo es su posición, contada desde 1, como toda posición de la biblioteca: order/lines/1 es la primera línea, order/lines/0 no designa nada — una escritura lo rechaza con -5. Un nivel se escribe como lo escribe JSON Pointer (RFC 6901): ~1 es un / de la clave y ~0 un ~ (paths/~1users lee la clave /users; of_escape_key convierte una clave), un nivel vacío es la clave "" (a//b), y una ruta puede empezar por / — la forma completa del puntero, la única manera de nombrar la clave "" de la raíz (/). Si un objeto escribe la misma clave dos veces, es su PRIMERA aparición la que se lee y se escribe — un navegador conserva la última.


Construir una carga útil #

MétodoFunción
of_add_string (string as_path, string as_value) → longAñade una CADENA, con escape automático, al ARRAY en as_path. El array debe existir: ábralo antes con of_set_raw y un array vacío. Devuelve 0, -4 si as_path falta o no es un array, -5 si un nivel de as_path es un índice 0 en un array; una cadena nula se escribe vacía (para un null JSON: of_add_raw(as_path, "null"))
of_add_boolean (string as_path, boolean ab_value) → longAñade un BOOLEANO (true o false, nunca entre comillas) al ARRAY en as_path. El array debe existir: ábralo antes con of_set_raw y un array vacío. Devuelve 0, -4 si as_path falta o no es un array, -5 si un nivel de as_path es un índice 0 en un array; un valor nulo escribe null
of_add_number (string as_path, long al_value) → longAñade un NÚMERO (cinco sobrecargas: integer, long, longlong, decimal, double — un decimal y un longlong conservan TODAS sus cifras (los céntimos de un importe, la última cifra de un identificador por encima de 2^53), y un literal como 690.50 es un decimal, escrito 690.5) al ARRAY en as_path. El array debe existir: ábralo antes con of_set_raw y un array vacío. Devuelve 0, -4 si as_path falta o no es un array, -5 si un nivel de as_path es un índice 0 en un array; un valor nulo escribe null
of_add_raw (string as_path, string as_json) → longAñade un valor YA en JSON (un objeto, un array) del que usted responde al ARRAY en as_path. El array debe existir: ábralo antes con of_set_raw y un array vacío. Devuelve 0, -4 si as_path falta o no es un array, -5 si un nivel de as_path es un índice 0 en un array; un valor nulo o vacío escribe null. La ruta vacía es la RAÍZ: of_load("[]") y luego of_add_raw("", …) construye un documento que es un array (el cuerpo de una llamada de API por lotes). Añadir muchos elementos seguidos al mismo array sigue siendo rápido
of_set_array (string as_path, string as_values[]) → longESCRIBE un ARRAY entero de cadenas en as_path desde un array PowerBuilder, cada elemento con escape. Un array vacío escribe uno vacío, un elemento nulo una cadena vacía. Misma regla de ruta y mismos códigos que of_set_string
of_set_members (string as_fragment) → longFusiona en la RAÍZ miembros ya formados en otro sitio, unidos por comas. Una clave que la raíz ya tiene ve su valor reemplazado en el sitio, una nueva se añade al final, una clave que el fragmento repite conserva su último valor. Un fragmento vacío no escribe nada. Devuelve 0, -4 si la raíz del documento no es un objeto
of_clear ( ) → longVacía el documento para empezar otro objeto con la misma variable. Devuelve 0
of_text ( ) → stringEl documento tal cual (compacto): lo que construyó (of_add_string, of_add_number...) o cargó (of_load), tras cualquier cambio — la salida única, lista para enviar, almacenar o reescribir. of_pretty da la forma indentada. {} si está vacío; llamarlo no vacía nada

Leer un documento #

MétodoFunción
of_load (string as_json) → longCarga un texto JSON para su lectura. Devuelve 0 si está bien formado, -5 si el argumento está vacío o en blanco (espacios, tabulaciones, saltos de línea), -4 si no es JSON válido o anida más de 512 niveles (el documento se descarta entonces). Analiza en PowerScript puro. Un BOM (U+FEFF) al principio, el de un archivo guardado en UTF-8 con BOM, se ignora. Con un código negativo, of_get_last_error dice dónde está mal el texto (línea, columna) y of_error_position en qué carácter. Un documento puede ser un solo valor ("abc", 42, null): se lee en la ruta vacía, no se escribe nada en él
of_is_valid ( ) → booleanVerdadero cuando el objeto contiene un documento: el último of_load tuvo éxito, o se ha escrito algo desde entonces. Un valor pasado a of_set_raw / of_add_raw no se vuelve a comprobar
of_exists (string as_path) → booleanVerdadero cuando existe un valor en la ruta dada — distingue un valor presente pero vacío de uno ausente
of_type (string as_path) → stringEl tipo JSON en la ruta: object, array, string, number, boolean, null; vacío si ausente
of_get_string (string as_path) → stringEl valor en la ruta, como texto: una cadena vuelve decodificada, un número/booleano/null como texto, un objeto o arreglo como JSON en bruto (recargable con of_load); una clave escrita dos veces se lee en su PRIMERA aparición
of_get_number (string as_path) → doubleEl número en la ruta, como double — el punto decimal se respeta en cualquier máquina (2.5 es 2,5, no 2). 0 si ausente; el exponente se resuelve (1e-7, 2.5E+3) y se conservan 17 cifras significativas, ceros iniciales del exponente incluidos. Para un importe o un identificador que debe conservar todas sus cifras: of_get_decimal o of_get_longlong. Una cadena solo cuenta si es entera un número JSON: "12.50" vale 12,5, "12 kg" y "1,5" valen 0
of_get_decimal (string as_path) → decimalEl número en la ruta, como decimal, reconstruido a partir del TEXTO del número y nunca mediante un double: 12345678901234.56 vuelve con sus céntimos, 2.5E-3 vale 0.0025. 28 cifras significativas como máximo. 0 si ausente, si el valor no es un número, o más allá de lo que cabe en un decimal; una cadena solo cuenta si es entera un número ("12.50")
of_get_longlong (string as_path) → longlongEl número en la ruta, como entero de 64 bits, reconstruido a partir de su texto y nunca mediante un double: un identificador de base de datos como 9007199254740993 vuelve entero. Los decimales se truncan (2.9 da 2). 0 si ausente, si el valor no es un número, o fuera del rango de un longlong; una cadena solo cuenta si es entera un número ("12.50")
of_get_boolean (string as_path) → booleanEl booleano en la ruta: verdadero para el literal JSON true y para la cadena "true" que escriben algunas API; falso para todo lo demás
of_count (string as_path) → longEl número de miembros del objeto, o de elementos del arreglo, en la ruta. Devuelve -1 si el valor es escalar o ausente (distingue un arreglo vacío, 0, de uno faltante, -1). Con of_name se recorre un objeto; un arreglo se recorre por su índice en la ruta (rows/1, rows/2…). Llamado en cada vuelta de un bucle, ya no cuesta nada una vez contado el arreglo, eliminaciones incluidas
of_name (string as_path, long al_index) → stringEl nombre del miembro n.º al_index (desde 1) del objeto en la ruta — para leer las claves de un objeto de forma desconocida. Con of_count, recorre el objeto. Para hacer de él un nivel de ruta: of_escape_key (una clave puede contener un /)
of_escape_key (string as_key) → stringUna CLAVE escrita como UN nivel de ruta (JSON Pointer, RFC 6901): un ~ se vuelve ~0, luego un / se vuelve ~1 — la clave application/json es el nivel application~1json. Lo que necesita una clave leída por of_name antes de entrar en una ruta
of_get_array (string as_path, ref string as_values[]) → longTodos los elementos del arreglo en la ruta, en orden, en as_values (vaciado antes) — cada uno como lo lee of_get_string: una cadena vuelve decodificada, un número o un booleano como texto, null como "", un objeto o un arreglo como JSON en bruto (para cargar con of_load en otro n_pbt_json). "" es la raíz. Devuelve el número de elementos (0 para un arreglo vacío), -4 cuando no hay un arreglo en la ruta (nada, un objeto, un escalar), -5 cuando un nivel de la ruta es un índice 0 sobre un arreglo
of_pretty ( ) → stringEl documento — cargado o construido — re-indentado para la lectura (varias líneas, tabulaciones) — un log, un cuadro de texto. Vacío si no hay ninguno, o si un valor puesto con of_set_raw anida más de 512 niveles (el texto no sería el documento)
of_pretty (long al_indent) → stringEl documento — cargado o construido — re-indentado con al_indent espacios por nivel (2 y 4 son los anchos habituales). 0 lo escribe compacto, en una línea y sin espacios: el texto más pequeño para almacenar o enviar. Vacío si no hay documento, o si al_indent es negativo, mayor que 16 o null, o si un valor puesto con of_set_raw anida más de 512 niveles. of_pretty() sin argumento conserva las tabulaciones
// 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)

Modificar un documento #

El lado de escritura cambia el documento cargado en el sitio, luego of_text devuelve el resultado (compacto) — lo que se reescribe. Los setters reemplazan el valor en la ruta, o agregan la última clave cuando falta en un objeto padre. Cada uno devuelve 0, -4 cuando un nivel del camino es un escalar, o un array sin ese índice, -5 con una ruta vacía o un índice 0 sobre un array. Un array encontrado en el camino se atraviesa con un índice que EXISTE (items/1/qty añade qty al primer elemento); solo se crea una clave de objeto. Un valor null (número, booleano, JSON en bruto vacío) se escribe null. Un bucle de escrituras, de claves añadidas o de eliminaciones en un documento grande (2 000 filas) sigue siendo rápido: cada llamada solo relee lo que toca.

MiembroFunción
of_set_string (string as_path, string as_value) → longESCRIBE una cadena en as_path, con escape automático. La ruta puede tener VARIOS niveles (a/b/c): los que faltan se crean como OBJETOS, y un documento VACÍO pasa a serlo — escribir ES construir. Un valor ya presente se reemplaza, esté donde esté. Una clave que contiene un / se escribe ~1 en la ruta (of_escape_key). Un bucle de escrituras en un documento grande sigue siendo rápido. Devuelve 0, -4 si un nivel del camino es un escalar, o un array sin ese índice (un array se atraviesa con un índice existente: items/1/qty), -5 con una ruta vacía o un índice 0 sobre un array. Una cadena nula se escribe vacía; para un null JSON: of_set_raw(as_path, "null")
of_set_number (string as_path, long al_value) → longESCRIBE un NÚMERO en as_path, el punto decimal forzado. Cinco sobrecargas: integer, long, longlong, decimal, double — un decimal y un longlong conservan TODAS sus cifras (los céntimos de un importe, la última cifra de un identificador por encima de 2^53), y un literal como 690.50 es un decimal, escrito 690.5. Misma regla de ruta y mismos códigos que of_set_string; un valor nulo escribe null
of_set_boolean (string as_path, boolean ab_value) → longESCRIBE un BOOLEANO en as_path: true o false, nunca entre comillas. Misma regla de ruta y mismos códigos que of_set_string; un valor nulo escribe null
of_set_raw (string as_path, string as_json) → longESCRIBE en as_path un valor YA en JSON — un objeto anidado, un array, null — tal cual: usted responde por él. Así se ABRE también un array antes de of_add_*. Misma regla de ruta y mismos códigos que of_set_string; un valor nulo o vacío escribe null
of_remove (string as_path) → longQuita el valor en la ruta — un miembro de objeto (su clave y una coma se van con él) o un elemento de arreglo; el resultado sigue siendo válido. Devuelve 0, -4 si no hay nada, -5 con una ruta vacía o un índice 0 sobre un array
// 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}

Fechas #

Una fecha se escribe y se lee en ISO 8601 — lo que escriben las API, los navegadores y Python —, sea cual sea el formato de fecha del equipo: una fecha "2026-10-10", una fecha-hora "2026-10-10T14:30:00" (su fracción de segundo sigue cuando no es nula), una hora "14:30:00". Un valor nulo escribe null.

MétodoFunción
of_set_date (string as_path, date ad_value) → longESCRIBE una fecha en as_path (yyyy-mm-dd). La misma regla de ruta que of_set_string: devuelve 0, -4 si un nivel del camino es un escalar o un array sin ese índice, -5 con una ruta vacía o un índice 0 sobre un array
of_set_datetime (string as_path, datetime adt_value) → longESCRIBE una fecha-hora (yyyy-mm-ddThh:mm:ss, la fracción de segundo tras un punto cuando no es nula). No se escribe ninguna zona horaria: la hora es la dada. Devuelve 0, -4 o -5, como of_set_date
of_set_time (string as_path, time at_value) → longESCRIBE una hora (hh:mm:ss). Devuelve 0, -4 o -5, como of_set_date
of_add_date (string as_path, date ad_value) → longAñade una fecha al ARRAY en as_path. Devuelve 0, -4 si as_path falta o no es un array, -5 si un nivel de as_path es un índice 0 en un array
of_add_datetime (string as_path, datetime adt_value) → longAñade una fecha-hora al ARRAY en as_path. Devuelve 0, -4 o -5, como of_add_date
of_add_time (string as_path, time at_value) → longAñade una hora al ARRAY en as_path. Devuelve 0, -4 o -5, como of_add_date
of_get_date (string as_path) → dateLa fecha escrita en la ruta ("2026-10-10", o la fecha de una fecha-hora). 1900-01-01 si el valor falta, no es una fecha o nombra un día que no existe (2026-02-30); of_exists y of_type distinguen un valor ausente
of_get_datetime (string as_path) → datetimeLa fecha-hora escrita en la ruta: una T o un espacio entre fecha y hora, con o sin segundos, con fracción de segundo, o una fecha sola (medianoche). Una Z o un desfase (+02:00) se lee y no se aplica: la hora es la escrita — conviértala usted cuando la zona importa. 1900-01-01 00:00:00 si falta o no es una fecha
of_get_time (string as_path) → timeLa hora escrita en la ruta ("14:30", "14:30:00", "14:30:00.250", o la hora de una fecha-hora). 00:00:00 si falta, no es una hora, o una fecha sola
// 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, y vuelta #

PowerBuilder solo tiene ExportJson e ImportJson a partir de la 2017 R2. n_pbt_json lo hace desde PowerBuilder 10, tipado por las columnas: una cadena, un número (un decimal conserva todas sus cifras), una fecha yyyy-mm-dd, una fecha-hora, una hora, null para un NULL. Una sobrecarga toma un datawindow, otra un datawindowchild.

MétodoFunción
of_from_datastore (string as_path, datastore ads_source) → longESCRIBE las filas del búfer principal como un ARRAY de objetos en as_path: un objeto por fila, un miembro por columna, con el nombre de la columna. La ruta vacía hace del DOCUMENTO ese array (el cuerpo de una llamada por lotes). Devuelve el número de filas escritas, -5 si el DataStore no es válido o no tiene columnas, si no lo que devuelve of_set_raw
of_to_datastore (string as_path, datastore ads_target) → longINSERTA el ARRAY de objetos en as_path en un DataStore: una fila por objeto, cada miembro en la columna del mismo nombre (sin distinguir mayúsculas), convertido al tipo de la columna — un número desde un número o desde una cadena que es entera un número, una fecha, una fecha-hora o una hora desde un texto ISO, NULL para un null o un valor que la columna no puede contener. Un miembro que no nombra ninguna columna se ignora, un elemento que no es un objeto no crea fila. Las filas son NUEVAS: Update las inserta. Devuelve el número de filas insertadas, -5 si el DataStore no es válido o no tiene columnas, -4 si no hay array en 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

Cuando el texto no es JSON #

MétodoFunción
of_get_last_error ( ) → stringPor qué la última llamada devolvió un código negativo; tras un of_load rechazado, dónde está mal el texto y por qué: line 2, column 6 : ':' expected after a key. Vacío tras una llamada correcta
of_error_position ( ) → longDevuelve la posición, contada desde 1 en el texto dado al último of_load (un BOM incluido), del carácter donde ese texto se vuelve erróneo — para seleccionar en un editor; 0 cuando el último of_load tuvo éxito
// 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

Alcance. El JSON se analiza en PowerScript puro, sin página ni motor: n_pbt_json sigue siendo autoinstantiate y funciona en todas partes, PowerBuilder 10 incluido. Para XML, vea xml (que se apoya en el motor); para mostrar un JSON como árbol plegable, vea jsontree.

← Referencia de componentes · Índice de la guía