1. Crea objetos/arrays dinámicos (JSON) - %DynamicObject, %DynamicArray, %FromJSON, %ToJSON
Puntos Clave
- %DynamicObject crea estructuras clave-valor similares a objetos JSON
- %DynamicArray crea listas ordenadas similares a arrays JSON
- %FromJSON() analiza una cadena JSON en un %DynamicObject o %DynamicArray
- %ToJSON() serializa un objeto/array dinámico de vuelta a una cadena JSON
- Las llaves `{}` y corchetes `[]` literales crean objetos y arrays dinámicos en línea
- Los objetos dinámicos no tienen esquema: no se requiere definición de clase
Notas Detalladas
Descripción general
InterSystems IRIS proporciona soporte nativo de JSON a través de %DynamicObject y %DynamicArray. Estas clases permiten crear, manipular y serializar datos JSON sin definir esquemas de clase formales. Son esenciales para construir APIs REST, procesar datos externos e intercambiar datos estructurados con otros sistemas.
Creación de Objetos Dinámicos
Usando el constructor %New():
Set obj = ##class(%DynamicObject).%New()
Do obj.%Set("name", "John Smith")
Do obj.%Set("age", 35, "number")
Do obj.%Set("active", 1, "boolean")
Write obj.%ToJSON()
// Output: {"name":"John Smith","age":35,"active":true}
Usando la sintaxis literal {} (preferida para casos simples):
Set obj = {"name": "John Smith", "age": 35, "active": true}
Write obj.%ToJSON()
// Output: {"name":"John Smith","age":35,"active":true}
Acceso a Propiedades
Set obj = {"name": "John", "age": 35}
// Dot syntax for simple property names
Write obj.name, ! // John
Write obj.age, ! // 35
// %Get() method for dynamic access
Set key = "name"
Write obj.%Get(key), ! // John
Modificación de Objetos Dinámicos
Set obj = {"name": "John"}
// Add/modify properties
Set obj.age = 35
Do obj.%Set("email", "john@example.com")
// Remove a property
Do obj.%Remove("email")
// Check if property exists
Write obj.%IsDefined("name") // 1
Write obj.%IsDefined("email") // 0
Creación de Arrays Dinámicos
Usando %New():
Set arr = ##class(%DynamicArray).%New()
Do arr.%Push("apple")
Do arr.%Push("banana")
Do arr.%Push("cherry")
Write arr.%ToJSON()
// Output: ["apple","banana","cherry"]
Usando la sintaxis literal []:
Set arr = ["apple", "banana", "cherry"]
Write arr.%ToJSON()
Operaciones con Arrays
Set arr = ["a", "b", "c", "d"]
// Access by index (0-based)
Write arr.%Get(0), ! // a
Write arr.%Get(2), ! // c
// Get array size
Write arr.%Size(), ! // 4
// Push to the end
Do arr.%Push("e")
// Pop from the end
Set last = arr.%Pop() // "e"
// Remove at index
Do arr.%Remove(1) // removes "b"
Análisis de JSON con %FromJSON()
Set jsonString = "{""name"":""Alice"",""scores"":[95,87,92]}"
Set obj = ##class(%DynamicAbstractObject).%FromJSON(jsonString)
// or equivalently:
Set obj = {}.%FromJSON(jsonString)
Write obj.name, ! // Alice
Write obj.scores.%Get(0), ! // 95
Write obj.scores.%Size(), ! // 3
Desde un stream:
Set stream = ##class(%Stream.GlobalCharacter).%New()
Do stream.Write("{""key"":""value""}")
Do stream.Rewind()
Set obj = ##class(%DynamicAbstractObject).%FromJSON(stream)
Write obj.key, ! // value
Estructuras Anidadas
Set person = {
"name": "Bob",
"address": {
"street": "123 Main St",
"city": "Springfield",
"state": "IL"
},
"phones": [
{"type": "home", "number": "555-1234"},
{"type": "work", "number": "555-5678"}
]
}
Write person.address.city, ! // Springfield
Write person.phones.%Get(0).number, ! // 555-1234
Write person.%ToJSON(), ! // Full JSON string
Iteración sobre Objetos Dinámicos
Set obj = {"name": "Alice", "age": 30, "city": "Boston"}
Set iter = obj.%GetIterator()
While iter.%GetNext(.key, .value) {
Write key, " = ", value, !
}
// Output:
// name = Alice
// age = 30
// city = Boston
Iteración sobre Arrays Dinámicos
Set arr = ["red", "green", "blue"]
Set iter = arr.%GetIterator()
While iter.%GetNext(.idx, .value) {
Write idx, ": ", value, !
}
// Output:
// 0: red
// 1: green
// 2: blue
Control de Tipo con %Set()
El tercer argumento de %Set() controla el tipo JSON:
Set obj = ##class(%DynamicObject).%New()
Do obj.%Set("count", 42, "number") // JSON number
Do obj.%Set("label", "42", "string") // JSON string "42"
Do obj.%Set("active", 1, "boolean") // JSON true
Do obj.%Set("deleted", 0, "boolean") // JSON false
Do obj.%Set("notes", "", "null") // JSON null
Write obj.%ToJSON()
// {"count":42,"label":"42","active":true,"deleted":false,"notes":null}
Verificación de Tipos de Valor
Set obj = {"name": "Test", "count": 5, "active": true, "data": null}
Write obj.%GetTypeOf("name"), ! // string
Write obj.%GetTypeOf("count"), ! // number
Write obj.%GetTypeOf("active"), ! // boolean
Write obj.%GetTypeOf("data"), ! // null
Write obj.%GetTypeOf("missing"), ! // unassigned
Referencias de Documentación
2. Usa objetos stream del tipo apropiado (%Stream.GlobalCharacter, %Stream.GlobalBinary, %Stream.FileCharacter, %Stream.FileBinary, Write(), Read(), Rewind())
Puntos Clave
- Los streams manejan datos demasiado grandes para variables de cadena (máx ~3.6M caracteres)
- Los streams de globals almacenan datos en globals de la base de datos (portátiles, respaldados con la base de datos)
- Los streams de archivos almacenan datos en archivos externos en el sistema de archivos
- Los streams de caracteres manejan datos de texto con soporte de codificación de caracteres
- Los streams binarios manejan datos binarios crudos (imágenes, PDFs, ejecutables)
- Operaciones principales: Write(), Read(), Rewind(), CopyFrom(), Clear()
Notas Detalladas
Descripción general
Los objetos stream proporcionan acceso secuencial a datos grandes. A diferencia de las propiedades de cadena que se cargan completamente en memoria, los streams pueden leerse y escribirse en fragmentos, haciéndolos adecuados para archivos, documentos y contenido binario de cualquier tamaño.
Guía de Selección de Tipo de Stream
| Necesidad | Clase de Stream | Almacenamiento |
|---|---|---|
| Texto grande en base de datos | %Stream.GlobalCharacter | Globals |
| Datos binarios en base de datos | %Stream.GlobalBinary | Globals |
| Archivos de texto en disco | %Stream.FileCharacter | Sistema de archivos |
| Archivos binarios en disco | %Stream.FileBinary | Sistema de archivos |
%Stream.GlobalCharacter - Texto en Base de Datos
// Create and write
Set stream = ##class(%Stream.GlobalCharacter).%New()
Do stream.Write("Line 1 of the document. ")
Do stream.WriteLine("Line 2 with newline.")
Do stream.Write("Line 3 continues.")
// Read back
Do stream.Rewind()
While 'stream.AtEnd {
Set chunk = stream.Read(1000)
Write chunk
}
Cuando se usa como propiedad en una clase persistente, los datos del stream se guardan automáticamente con el objeto:
Class Sample.Document Extends %Persistent
{
Property Title As %String(MAXLEN = 200);
Property Body As %Stream.GlobalCharacter;
ClassMethod CreateDoc(title As %String, text As %String) As %Status
{
Set doc = ##class(Sample.Document).%New()
Set doc.Title = title
Do doc.Body.Write(text)
Return doc.%Save()
}
}
%Stream.GlobalBinary - Binario en Base de Datos
Class Sample.Attachment Extends %Persistent
{
Property Filename As %String;
Property Content As %Stream.GlobalBinary;
Property ContentType As %String;
}
// Store binary data
Set att = ##class(Sample.Attachment).%New()
Set att.Filename = "report.pdf"
Set att.ContentType = "application/pdf"
// Read from a file stream and copy to global stream
Set fileStream = ##class(%Stream.FileBinary).%New()
Set fileStream.Filename = "/path/to/report.pdf"
Do att.Content.CopyFrom(fileStream)
Set sc = att.%Save()
%Stream.FileCharacter - Texto en Sistema de Archivos
// Write to an external file
Set stream = ##class(%Stream.FileCharacter).%New()
Set stream.Filename = "/tmp/output.csv"
Do stream.Write("Name,Age,City")
Do stream.WriteLine("")
Do stream.Write("Alice,30,Boston")
Do stream.WriteLine("")
Set sc = stream.%Save()
// Read from an external file
Set stream = ##class(%Stream.FileCharacter).%New()
Set stream.Filename = "/tmp/output.csv"
Do stream.Rewind()
While 'stream.AtEnd {
Set line = stream.ReadLine()
Write line, !
}
%Stream.FileBinary - Binario en Sistema de Archivos
// Read a binary file
Set stream = ##class(%Stream.FileBinary).%New()
Set stream.Filename = "/path/to/image.png"
Write "File size: ", stream.Size, " bytes", !
// Copy to another location
Set target = ##class(%Stream.FileBinary).%New()
Set target.Filename = "/path/to/copy.png"
Do target.CopyFrom(stream)
Set sc = target.%Save()
Referencia de Métodos Principales de Streams
| Método/Propiedad | Descripción |
|---|---|
| Write(data) | Agrega datos en la posición actual |
| WriteLine(data) | Agrega datos seguidos de un terminador de línea de plataforma |
| Read(len) | Lee hasta len caracteres/bytes desde la posición actual |
| ReadLine(len, .sc, .eol) | Lee una línea (hasta len caracteres) |
| Rewind() | Reinicia la posición al principio del stream |
| MoveToEnd() | Mueve la posición al final (para agregar) |
| Clear() | Elimina todo el contenido del stream |
| CopyFrom(source) | Copia todo el contenido desde otro stream |
| Size | Devuelve el tamaño total en caracteres/bytes |
| AtEnd | Devuelve 1 si está al final del stream, 0 en caso contrario |
Patrones de Procesamiento de Streams
Lectura en fragmentos de tamaño fijo (para streams grandes):
Set chunkSize = 32000
Do stream.Rewind()
While 'stream.AtEnd {
Set chunk = stream.Read(chunkSize)
// Process chunk
}
Lectura línea por línea (para streams de texto):
Do stream.Rewind()
While 'stream.AtEnd {
Set line = stream.ReadLine()
// Process each line
}
Agregar a un stream existente:
// Position at the end before writing more data
Do stream.MoveToEnd()
Do stream.Write("Additional content appended.")
Set sc = stream.%Save()
Codificación de Caracteres con Streams de Archivo
Los streams de caracteres de archivo soportan la propiedad TranslateTable para codificación de caracteres:
Set stream = ##class(%Stream.FileCharacter).%New()
Set stream.Filename = "/tmp/utf8file.txt"
Set stream.TranslateTable = "UTF8"
Do stream.Write("Content with special characters: accents, symbols")
Set sc = stream.%Save()
Comparación de Streams
// Check if two streams have identical content
Set same = stream1.%ConstructClone().Equals(stream2)
// Or use SizeGet for a quick size comparison first
If stream1.Size '= stream2.Size {
Write "Streams differ (different sizes)", !
}
Referencias de Documentación
Resumen de Preparación para el Examen
Conceptos Críticos a Dominar:
- `{}` crea un %DynamicObject; `[]` crea un %DynamicArray (sintaxis literal)
- %FromJSON() analiza cadenas JSON o streams en objetos/arrays dinámicos
- %ToJSON() serializa objetos/arrays dinámicos de vuelta a cadenas JSON
- Los arrays dinámicos tienen índice basado en 0; usar %Get(index), %Push(), %Pop(), %Size()
- %GetIterator() es la forma correcta de iterar sobre objetos y arrays dinámicos
- %Set() con un tercer argumento controla el tipo JSON (number, string, boolean, null)
- Cuatro tipos de stream: GlobalCharacter, GlobalBinary, FileCharacter, FileBinary
- Los streams usan el patrón Write/Read/Rewind (no asignación directa de propiedad)
- CopyFrom() copia contenido entre cualesquier dos streams
- La propiedad AtEnd controla los bucles de lectura; Rewind() reinicia al principio
- Los streams de globals se almacenan en la base de datos; los streams de archivos en el sistema de archivos externo
- Los streams de caracteres manejan texto con codificación; los streams binarios manejan bytes crudos
Escenarios Comunes en el Examen:
- Crear una respuesta JSON desde datos ObjectScript usando %DynamicObject
- Analizar JSON entrante en un objeto dinámico y acceder a valores anidados
- Elegir el tipo de stream correcto para un caso de uso dado (texto vs binario, base de datos vs archivo)
- Escribir código para leer un stream fragmento por fragmento o línea por línea
- Convertir entre tipos de stream usando CopyFrom()
- Identificar el método correcto para verificar tipos de valor JSON (%GetTypeOf)
Recomendaciones de Práctica:
- Construir estructuras JSON anidadas usando tanto la sintaxis literal como los métodos %Set/%Push
- Analizar cadenas JSON de ejemplo con %FromJSON() y navegar la estructura resultante
- Crear cada uno de los cuatro tipos de stream, escribir datos y leerlos de vuelta
- Practicar CopyFrom() para transferir datos entre streams de globals y de archivos
- Usar %GetIterator() para iterar sobre objetos y arrays dinámicos
- Construir un manejador REST simple que acepte y devuelva JSON usando objetos dinámicos