Trabajar con datos JSON en Business Central es una tarea habitual cuando interactuamos con APIs, servicios externos o almacenamos información estructurada. Afortunadamente, Microsoft ofrece una herramienta estándar que hace esta labor mucho más sencilla: la Codeunit "JSON Management".
En este post, te mostraré cómo aprovechar sus capacidades para manipular datos JSON de manera eficiente. Además, integraremos algunas funciones útiles para simplificar tareas cotidianas.
¡Vamos manos a la obra! 😤
🧩 ¿Qué es la Codeunit JSON Management?
La Codeunit "JSON Management" es una herramienta estándar de Business Central que facilita el manejo de datos en formato JSON. Permite trabajar con objetos, colecciones y valores individuales de manera clara y eficiente, sin necesidad de escribir lógica compleja desde cero.
🎯 Principales capacidades:
- Inicializar objetos JSON
- Extraer y modificar valores
- Trabajar con arreglos JSON (JsonArray)
- Convertir entre texto y objetos JSON
Esta Codeunit es esencial cuando necesitas comunicarte con servicios externos a través de APIs REST o cualquier fuente que use JSON como formato de intercambio de datos.
🧩 Extrayendo datos con GetValueText
Una de las tareas más comunes al trabajar con JSON es extraer el valor de una clave específica. Veamos cómo hacerlo con la Codeunit JSON Management:
procedure GetValueText(Json: Text; Tag: Text) ReturnValue: Text;
var
JSONManagement: Codeunit "JSON Management";
begin
Clear(JSONManagement);
JSONManagement.InitializeObject(Json);
ReturnValue := JSONManagement.GetValue(Tag);
end;
🔍 ¿Qué ocurre aquí?
- Inicializamos un objeto JSON usando
InitializeObject. - Buscamos el valor asociado a la clave indicada con
GetValue(Tag). - Devolvemos el valor encontrado como un
Text.
🛠️ Aplicación práctica:
Supongamos que recibes un JSON con información de un pedido y necesitas el CustomerName. Con esta función, lo obtienes en una sola llamada.
🧱 Convirtiendo Text en JsonObject con GetValueJsonObject
A veces, el valor asociado a una clave no es un texto simple, sino un objeto JSON anidado. En esos casos, necesitamos convertirlo a un JsonObject:
procedure GetValueJsonObject(Json: Text; Tag: Text) ReturnValue: JsonObject;
var
ValueText: Text;
begin
ValueText := this.GetValueText(Json, Tag);
ReturnValue.ReadFrom(ValueText);
end;
🔍 ¿Qué hace esta función?
- Obtiene el valor como
Textutilizando la funciónGetValueText. - Convierte el texto en un
JsonObjectmedianteReadFrom(ValueText).
🛠️ Aplicación práctica:
Cuando una respuesta JSON de una API devuelve un objeto con múltiples propiedades, esta función permite manejarlo como un JsonObject para acceder fácilmente a sus campos.
📦 Accediendo a elementos de un JsonArray con GetValueFromJsonArray
Los datos JSON suelen contener listas o arreglos, por ejemplo, una lista de productos o transacciones. Para acceder a un elemento específico por su índice, usamos esta función:
procedure GetValueFromJsonArray(Json: Text; Index: Integer) ReturnValue: Text;
var
JSONManagement: Codeunit "JSON Management";
begin
Clear(JSONManagement);
JSONManagement.InitializeCollection(Json);
JSONManagement.GetObjectFromCollectionByIndex(ReturnValue, Index);
end;
🔍 ¿Qué sucede aquí?
- Inicializamos una colección JSON con
InitializeCollection. - Accedemos al elemento del índice solicitado con
GetObjectFromCollectionByIndex. - Devolvemos el valor en formato
Text.
🛠️ Aplicación práctica:
Ideal cuando se trabaja con listas de artículos, líneas de factura o cualquier conjunto de datos repetidos dentro de un JSON.
✅ Verificando la existencia de un valor con HasValue
Antes de acceder a una clave en un JSON, es importante comprobar si existe. Esta función se encarga de hacerlo:
procedure HasValue(Json: Text; Tag: Text) ReturnValue: Boolean
var
ValueText: Text;
begin
Clear(ReturnValue);
ValueText := this.GetValueText(Json, Tag);
if ValueText <> '' then
ReturnValue := true;
end;
🔍 ¿Cómo funciona?
- Busca el valor de la clave solicitada usando
GetValueText. - Comprueba si el valor está vacío y devuelve
truesi existe.
🛠️ Aplicación práctica:
Es muy útil al trabajar con estructuras JSON dinámicas, donde no todas las claves están garantizadas.
🚀 ¿Por qué usar la Codeunit JSON Management?
🌟 Ventajas clave
- Integración nativa: No necesitas bibliotecas externas, todo se gestiona dentro de Business Central.
- Código simplificado: Funciones claras y bien definidas para tareas comunes.
- Eficiencia garantizada: Operaciones optimizadas por Microsoft, listas para producción.
🌐 Aplicaciones prácticas
- Integración con APIs REST: Procesamiento de respuestas JSON en integraciones con CRM, e-commerce y otros sistemas.
- Procesamiento de datos estructurados: Análisis de grandes volúmenes de información en formato JSON.
- Exportación e importación de datos: Generación y consumo de JSON para intercambio de datos con aplicaciones externas.
🎯 Ejemplo práctico:
Imagina una integración con un sistema de logística. Al recibir un JSON con el estado de un envío, puedes usar la Codeunit JSON Management para extraer el campo status y reflejarlo en Business Central.
🔄 Conversión bidireccional Registro ↔ JSON con Advanced Mgt. Json
Además de la Codeunit JSON Management estándar, existe una codeunit personalizada —Advanced Mgt. Json— que permite convertir registros completos de Business Central a JSON y viceversa, usando RecordRef y FieldRef para que funcione con cualquier tabla sin escribir código específico por tabla.
El código original está basado en el trabajo de Erik Hougaard y ha sido modificado y adaptado.
📥 Importar JSON a un registro: UploadJson2Rec
procedure UploadJson2Rec(RecVariant: Variant): Variant
var
RecordRefe: RecordRef;
begin
RecordRefe.GetTable(RecVariant);
exit(UploadJson2Rec(RecordRefe.Number()));
end;
procedure UploadJson2Rec(TableNo: Integer): Variant
var
JObject: JsonObject;
FileName: Text;
DocInStream: InStream;
begin
if not UploadIntoStream('', '', '', FileName, DocInStream) then
exit;
Clear(JObject);
JObject.ReadFrom(DocInStream);
exit(Json2Rec(JObject, TableNo));
end;
UploadJson2Rec abre un diálogo de selección de archivo, lee el JSON del fichero elegido y lo convierte en un registro de la tabla indicada. Tiene dos sobrecargas: una acepta un Variant (infiere el número de tabla) y otra acepta directamente el número de tabla.
🔁 Convertir JsonObject a registro: Json2Rec
procedure Json2Rec(JObject: JsonObject; RecVariant: Variant): Variant
var
RecordRefe: RecordRef;
begin
RecordRefe.GetTable(RecVariant);
exit(Json2Rec(JObject, RecordRefe.Number()));
end;
procedure Json2Rec(JObject: JsonObject; TableNo: Integer): Variant
var
RecordRefe: RecordRef;
FieldRefe: FieldRef;
FieldHash: Dictionary of [Text, Integer];
i: Integer;
JsonKey: Text;
JToken: JsonToken;
JsonValueKey: JsonValue;
RecVariant: Variant;
begin
RecordRefe.OPEN(TableNo);
for i := 1 to RecordRefe.FieldCount() do begin
FieldRefe := RecordRefe.FieldIndex(i);
FieldHash.Add(GetJsonFieldName(FieldRefe), FieldRefe.Number);
end;
RecordRefe.Init();
foreach JsonKey in JObject.Keys() do begin
if JObject.Get(JsonKey, JToken) then begin
if JToken.IsValue() then begin
JsonValueKey := JToken.AsValue();
FieldRefe := RecordRefe.Field(FieldHash.Get(JsonKey));
AssignValueToFieldRef(FieldRefe, JsonValueKey);
end;
end;
end;
RecordRefe.Insert();
RecVariant := RecordRefe;
exit(RecVariant);
end;
Json2Rec toma un JsonObject ya cargado y lo convierte en un registro insertado en la tabla indicada. Internamente construye un Dictionary mapeando nombre de campo JSON → número de campo, y luego recorre las claves del JSON asignando cada valor al campo correspondiente mediante FieldRef.
📤 Convertir registro a JsonObject: Rec2Json
procedure Rec2Json(Rec: Variant): JsonObject
var
RecordRefe: RecordRef;
FieldRefe: FieldRef;
JObject: JsonObject;
JValue: JsonValue;
i: Integer;
Tet001Lbl: Label 'Parameter Rec is not a record', comment = 'ESP="El parámetro Rec no es un registro"';
begin
if not Rec.IsRecord then
error(Text001Lbl);
RecordRefe.GetTable(Rec);
for i := 1 to RecordRefe.FieldCount() do begin
FieldRefe := RecordRefe.FieldIndex(i);
case FieldRefe.Class of
FieldRefe.Class::Normal:
begin
Clear(JValue);
JValue := FieldRef2JsonValue(FieldRefe);
if Not JValue.IsNull then
JObject.Add(GetJsonFieldName(FieldRefe), JValue);
end;
FieldRefe.Class::FlowField:
begin
FieldRefe.CalcField();
JValue := FieldRefToJsonValue(FieldRefe);
if Not JValue.IsNull then
JObject.Add(GetJsonFieldName(FieldRefe), JValue);
end;
end;
end;
exit(JObject);
end;
Rec2Json es la operación inversa: recorre todos los campos de un registro (campos normales y FlowFields) y construye un JsonObject con ellos. Los FlowFields se calculan antes de añadirse. Si el valor de un campo es nulo, no se añade al JSON.
🛠️ Aplicaciones prácticas del bloque AdvancedMgtJson:
- Exportar cualquier registro de BC a un fichero JSON sin código específico por tabla.
- Importar un fichero JSON y crear registros automáticamente en cualquier tabla.
- Sincronización de datos entre entornos o empresas usando JSON como formato intermedio.
- Base para herramientas de migración o copia de datos genéricas.
🏁 Conclusión
La Codeunit "JSON Management" de Business Central es una herramienta poderosa que facilita la manipulación de datos estructurados en formato JSON. Con las funciones descritas, puedes extraer, convertir, verificar y procesar información de manera clara y eficiente. Además, el bloque Advanced Mgt. Json amplía estas capacidades con conversión bidireccional genérica entre cualquier registro y JSON.
Si quieres ver el código completo, está en GitHub (MgtJson) y en GitHub (AdvancedMgtJson).
¡Hasta la próxima!