Supporto JSON in Delphi: Guida Completa con Esempi (2025)
JSON (JavaScript Object Notation) è lo standard de-facto per lo scambio di dati nelle applicazioni moderne. Che tu stia costruendo REST API, leggendo file di configurazione o comunicando con web services, comprendere come lavorare con JSON in Delphi è essenziale.
Questa guida completa copre tutto ciò che devi sapere sul supporto JSON in Delphi, con esempi completi e compilabili che puoi usare nei tuoi progetti.
TJSONObject, TJSONArray). Per il parsing in stile streaming/SAX, consulta le unit System.JSON.Readers e System.JSON.Writers.
Compatibilità tra le Versioni di Delphi
Il supporto JSON si è evoluto significativamente tra le varie versioni di Delphi:
| Versione | Unit | Caratteristiche Principali |
|---|---|---|
| Delphi 2009 | DBXJSON |
Supporto JSON iniziale con classi base |
| Delphi XE6 | System.JSON |
Unit rinominata, API migliorata |
| Delphi 10.1 Berlin | System.JSON |
API fluent TJSONObjectBuilder, miglioramenti a TryGetValue<T> |
| Delphi 10.3 Rio | System.JSON |
Metodo Format(), EJSONParseException con dettagli, miglioramenti delle prestazioni |
| Delphi 11-12 | System.JSON |
Ulteriori ottimizzazioni e perfezionamenti |
| Delphi 13 Florence | System.JSON |
Ultimi miglioramenti e supporto continuo |
Cos’è JSON?
JSON è un formato leggero di scambio dati basato su testo. È facile da leggere e scrivere per gli umani, e facile da analizzare e generare per le macchine. Un documento JSON può contenere:
- Oggetti: Coppie chiave-valore racchiuse tra parentesi graffe
{} - Array: Liste ordinate di valori racchiuse tra parentesi quadre
[] - Valori: Stringhe, numeri, booleani (
true/false),null, oggetti o array
Esempio di struttura JSON:
{
"name": "Daniele Teti",
"age": 45,
"active": true,
"skills": ["Delphi", "Python", "SQL"],
"address": {
"city": "Rome",
"country": "Italy"
}
}
Panoramica delle Classi JSON di Delphi
Delphi fornisce supporto JSON integrato tramite l’unit System.JSON. Le classi principali sono:
| Classe | Descrizione |
|---|---|
TJSONValue |
Classe base per tutti i tipi di valori JSON |
TJSONObject |
Rappresenta un oggetto JSON (coppie chiave-valore) |
TJSONArray |
Rappresenta un array JSON (lista ordinata) |
TJSONString |
Rappresenta un valore stringa JSON |
TJSONNumber |
Rappresenta un valore numerico JSON |
TJSONBool |
Rappresenta un valore booleano JSON |
TJSONNull |
Rappresenta un valore null JSON |
TJSONPair |
Rappresenta una coppia chiave-valore in un oggetto |
Creazione di Oggetti JSON
Iniziamo dalle basi: creare oggetti JSON e aggiungere proprietà.
Creazione Base di Oggetti JSON
L’operazione più fondamentale è creare un TJSONObject e aggiungervi coppie chiave-valore. Delphi fornisce pratici overload di AddPair che accettano direttamente stringhe, interi, booleani e double - non è necessario avvolgere i valori primitivi in classi specifiche per JSON. L’esempio seguente dimostra come costruire un semplice oggetto JSON contenente informazioni personali con vari tipi di dati:
program JSONCreateBasic;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
var
LJSONObject: TJSONObject;
begin
LJSONObject := TJSONObject.Create;
try
// Aggiungi proprietà stringa
LJSONObject.AddPair('firstName', 'Daniele');
LJSONObject.AddPair('lastName', 'Teti');
// Aggiungi proprietà numerica (sono disponibili overload per Integer, Int64, Double)
LJSONObject.AddPair('age', 45);
// Aggiungi proprietà booleana
LJSONObject.AddPair('active', True);
// Aggiungi proprietà null (nessun overload - deve usare TJSONNull)
LJSONObject.AddPair('middleName', TJSONNull.Create);
// Stampa il JSON
// Nota: Format() disponibile da Delphi 10.3 Rio
{$IF CompilerVersion >= 33.0} // Delphi 10.3 Rio
WriteLn(LJSONObject.Format());
{$ELSE}
WriteLn(LJSONObject.ToString);
{$ENDIF}
finally
LJSONObject.Free;
end;
ReadLn;
end.
Output:
{
"firstName": "Daniele",
"lastName": "Teti",
"age": 45,
"active": true,
"middleName": null
}
Creazione di Array JSON
Gli array JSON sono collezioni ordinate che possono contenere qualsiasi combinazione di valori - stringhe, numeri, booleani o anche altri array e oggetti. Quando aggiungi un TJSONArray a un TJSONObject usando AddPair, l’oggetto genitore assume la proprietà dell’array, quindi devi liberare solo l’oggetto root. Questo esempio mostra come creare sia un array omogeneo di stringhe che un array a tipo misto:
program JSONCreateArray;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
var
LJSONObject: TJSONObject;
LContacts: TJSONArray;
LSkills: TJSONArray;
begin
LJSONObject := TJSONObject.Create;
try
LJSONObject.AddPair('name', 'Daniele Teti');
// Crea array di stringhe
LSkills := TJSONArray.Create;
LJSONObject.AddPair('skills', LSkills);
LSkills.Add('Delphi');
LSkills.Add('Python');
LSkills.Add('SQL');
// Crea array con tipi misti
LContacts := TJSONArray.Create;
LJSONObject.AddPair('contacts', LContacts);
LContacts.Add('daniele@example.com'); // stringa
LContacts.Add(123456); // numero
LContacts.Add(True); // booleano
{$IF CompilerVersion >= 33.0}
WriteLn(LJSONObject.Format());
{$ELSE}
WriteLn(LJSONObject.ToString);
{$ENDIF}
finally
LJSONObject.Free; // Libera anche LContacts e LSkills
end;
ReadLn;
end.
Output:
{
"name": "Daniele Teti",
"skills": [
"Delphi",
"Python",
"SQL"
],
"contacts": [
"daniele@example.com",
123456,
true
]
}
Creazione di un Array di Oggetti
Uno dei pattern più comuni nel JSON del mondo reale è un array contenente più oggetti - pensa a una lista di utenti, prodotti o qualsiasi collezione di record. Ogni oggetto nell’array può avere il proprio insieme di proprietà. Quando costruisci questa struttura, crei ogni oggetto separatamente e lo aggiungi all’array usando il metodo Add. L’array possiede quindi tutti gli oggetti che aggiungi:
program JSONArrayOfObjects;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
var
LRoot: TJSONObject;
LUsers: TJSONArray;
LUser: TJSONObject;
begin
LRoot := TJSONObject.Create;
try
LUsers := TJSONArray.Create;
LRoot.AddPair('users', LUsers);
// Primo utente
LUser := TJSONObject.Create;
LUsers.Add(LUser);
LUser.AddPair('id', 1);
LUser.AddPair('name', 'Alice');
LUser.AddPair('email', 'alice@example.com');
// Secondo utente
LUser := TJSONObject.Create;
LUsers.Add(LUser);
LUser.AddPair('id', 2);
LUser.AddPair('name', 'Bob');
LUser.AddPair('email', 'bob@example.com');
// Terzo utente
LUser := TJSONObject.Create;
LUsers.Add(LUser);
LUser.AddPair('id', 3);
LUser.AddPair('name', 'Charlie');
LUser.AddPair('email', 'charlie@example.com');
{$IF CompilerVersion >= 33.0}
WriteLn(LRoot.Format());
{$ELSE}
WriteLn(LRoot.ToString);
{$ENDIF}
finally
LRoot.Free;
end;
ReadLn;
end.
Output:
{
"users": [
{
"id": 1,
"name": "Alice",
"email": "alice@example.com"
},
{
"id": 2,
"name": "Bob",
"email": "bob@example.com"
},
{
"id": 3,
"name": "Charlie",
"email": "charlie@example.com"
}
]
}
Oggetti JSON Annidati
I dati complessi richiedono spesso un’organizzazione gerarchica - una persona ha un indirizzo, un indirizzo ha città e paese, e così via. In Delphi, crei strutture annidate aggiungendo istanze TJSONObject come valori all’interno di altri oggetti. Proprio come con gli array, l’oggetto genitore assume la proprietà dei suoi figli, semplificando la gestione della memoria. Questo esempio crea una persona con oggetti annidati per indirizzo e azienda:
program JSONNested;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
var
LJSONObject: TJSONObject;
LAddress: TJSONObject;
LCompany: TJSONObject;
begin
LJSONObject := TJSONObject.Create;
try
LJSONObject.AddPair('name', 'Daniele Teti');
// Crea oggetto indirizzo annidato
LAddress := TJSONObject.Create;
LJSONObject.AddPair('address', LAddress);
LAddress.AddPair('street', 'Via Roma 123');
LAddress.AddPair('city', 'Rome');
LAddress.AddPair('country', 'Italy');
LAddress.AddPair('zipCode', '00100');
// Crea un altro oggetto annidato
LCompany := TJSONObject.Create;
LJSONObject.AddPair('company', LCompany);
LCompany.AddPair('name', 'bit Time Professionals');
LCompany.AddPair('website', 'https://www.bittime.it');
{$IF CompilerVersion >= 33.0}
WriteLn(LJSONObject.Format());
{$ELSE}
WriteLn(LJSONObject.ToString);
{$ENDIF}
finally
LJSONObject.Free;
end;
ReadLn;
end.
Output:
{
"name": "Daniele Teti",
"address": {
"street": "Via Roma 123",
"city": "Rome",
"country": "Italy",
"zipCode": "00100"
},
"company": {
"name": "bit Time Professionals",
"website": "https://www.bittime.it"
}
}
Uso di TJSONObjectBuilder (Delphi 10.1 Berlin+)
Se preferisci una sintassi più dichiarativa e concatenabile per costruire JSON, Delphi 10.1 Berlin ha introdotto TJSONObjectBuilder. Questa API fluent ti permette di costruire strutture JSON complesse in una singola espressione usando il concatenamento di metodi con BeginObject, BeginArray, Add e chiamate EndObject/EndArray. Il builder scrive su un TJsonTextWriter, che scrive su un TStringBuilder. Sebbene più verboso nella configurazione, questo approccio produce codice più pulito e leggibile per strutture complesse:
program JSONBuilderExample;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.Classes,
System.JSON.Types,
System.JSON.Writers,
System.JSON.Builders;
var
LBuilder: TJSONObjectBuilder;
LWriter: TJsonTextWriter;
LStringWriter: TStringWriter;
LStringBuilder: TStringBuilder;
begin
LStringBuilder := TStringBuilder.Create;
try
LStringWriter := TStringWriter.Create(LStringBuilder);
try
LWriter := TJsonTextWriter.Create(LStringWriter);
try
LWriter.Formatting := TJsonFormatting.Indented;
LBuilder := TJSONObjectBuilder.Create(LWriter);
try
// Costruisci JSON usando l'API fluent
LBuilder
.BeginObject
.Add('firstName', 'Daniele')
.Add('lastName', 'Teti')
.Add('age', 45)
.Add('active', True)
.BeginObject('address')
.Add('city', 'Rome')
.Add('country', 'Italy')
.EndObject
.BeginArray('skills')
.Add('Delphi')
.Add('Python')
.Add('SQL')
.EndArray
.EndObject;
WriteLn(LStringBuilder.ToString);
finally
LBuilder.Free;
end;
finally
LWriter.Free;
end;
finally
LStringWriter.Free;
end;
finally
LStringBuilder.Free;
end;
ReadLn;
end.
Output:
{
"firstName": "Daniele",
"lastName": "Teti",
"age": 45,
"active": true,
"address": {
"city": "Rome",
"country": "Italy"
},
"skills": [
"Delphi",
"Python",
"SQL"
]
}
Parsing di Stringhe JSON
Quando ricevi dati JSON da un web service, file o qualsiasi altra sorgente, devi analizzarli in oggetti Delphi con cui puoi lavorare. Il metodo di classe TJSONObject.ParseJSONValue gestisce questa conversione. Restituisce un TJSONValue (la classe base), quindi dovrai controllare se è del tipo atteso - tipicamente TJSONObject o TJSONArray. Se il JSON è malformato, il metodo restituisce nil, quindi controlla sempre questo prima di procedere:
program JSONParsing;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
const
JSON_STRING =
'{"name":"Daniele","age":45,"skills":["Delphi","Python"]}';
var
LJSONValue: TJSONValue;
LJSONObject: TJSONObject;
begin
// ParseJSONValue restituisce TJSONValue, converti al tipo appropriato
LJSONValue := TJSONObject.ParseJSONValue(JSON_STRING);
if LJSONValue = nil then
begin
WriteLn('ERRORE: JSON non valido!');
ReadLn;
Exit;
end;
try
// Controlla se è un oggetto (potrebbe essere un array a livello root)
if not (LJSONValue is TJSONObject) then
begin
WriteLn('ERRORE: Atteso oggetto JSON a livello root');
Exit;
end;
LJSONObject := TJSONObject(LJSONValue); // Cast diretto - sicuro dopo il controllo "is"
WriteLn('Analisi riuscita!');
WriteLn('Numero di coppie: ', LJSONObject.Count);
{$IF CompilerVersion >= 33.0}
WriteLn(LJSONObject.Format());
{$ELSE}
WriteLn(LJSONObject.ToString);
{$ENDIF}
finally
LJSONValue.Free;
end;
ReadLn;
end.
ParseJSONValue restituisce nil, che indica JSON non valido.
Gestione degli Errori di Parsing (Delphi 10.3+)
Quando il parsing fallisce, sapere perché è fallito aiuta enormemente il debugging. A partire da Delphi 10.3 Rio, puoi passare True come secondo parametro a ParseJSONValue per fargli sollevare un’eccezione EJSONParseException invece di restituire nil. Questa eccezione include il messaggio di errore, il percorso dove il parsing è fallito e l’offset del carattere - informazioni preziosissime quando si ha a che fare con JSON complesso o fornito esternamente:
program JSONParseErrors;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
const
INVALID_JSON = '{"name": "Test", "value": }'; // Non valido!
var
LJSONValue: TJSONValue;
begin
{$IF CompilerVersion >= 33.0} // Delphi 10.3 Rio
try
// Usa l'opzione RaiseExc per ottenere l'eccezione con i dettagli
LJSONValue := TJSONObject.ParseJSONValue(INVALID_JSON, True);
try
WriteLn('Analizzato: ', LJSONValue.ToString);
finally
LJSONValue.Free;
end;
except
on E: EJSONParseException do
begin
WriteLn('Errore di parsing!');
WriteLn(' Messaggio: ', E.Message);
WriteLn(' Percorso: ', E.Path);
WriteLn(' Offset: ', E.Offset);
end;
end;
{$ELSE}
// Pre-10.3: controlla solo nil
LJSONValue := TJSONObject.ParseJSONValue(INVALID_JSON);
if LJSONValue = nil then
WriteLn('JSON non valido - nessun dettaglio disponibile')
else
LJSONValue.Free;
{$ENDIF}
ReadLn;
end.
Lettura di Valori JSON
Delphi fornisce diversi modi per leggere valori da oggetti JSON, ognuno con diversi compromessi tra comodità e sicurezza. Capire quando usare ciascun approccio ti aiuterà a scrivere codice più robusto che gestisce i dati mancanti o inaspettati con eleganza.
Metodo 1: GetValue con Tipo Generico (Delphi XE7+)
Il modo più semplice per leggere un valore è usare il metodo generico GetValue<T>. Specifichi il tipo atteso come parametro di tipo e Delphi gestisce automaticamente la conversione. Tuttavia, questo metodo solleva un’eccezione se la chiave non esiste, quindi usalo solo quando sei certo che la chiave è presente:
program JSONReadGetValue;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
const
JSON_DATA = '{"name":"Daniele","age":45,"active":true}';
var
LJSONObject: TJSONObject;
begin
LJSONObject := TJSONObject.ParseJSONValue(JSON_DATA) as TJSONObject;
try
// GetValue<T> - solleva eccezione se la chiave non è trovata
WriteLn('Nome: ', LJSONObject.GetValue<string>('name'));
WriteLn('Età: ', LJSONObject.GetValue<Integer>('age'));
WriteLn('Attivo: ', LJSONObject.GetValue<Boolean>('active'));
finally
LJSONObject.Free;
end;
ReadLn;
end.
Metodo 2: TryGetValue - Lettura Sicura (Consigliato)
Per il codice di produzione, TryGetValue<T> è l’approccio consigliato. Restituisce False se la chiave manca o il valore non può essere convertito al tipo richiesto, permettendoti di gestire i dati mancanti senza gestione delle eccezioni. Questo è particolarmente utile quando si analizza JSON da fonti esterne dove non puoi garantire che tutti i campi siano presenti:
program JSONReadTryGetValue;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
const
JSON_DATA = '{"name":"Daniele","age":45}';
var
LJSONObject: TJSONObject;
LName: string;
LAge: Integer;
LMiddleName: string;
begin
LJSONObject := TJSONObject.ParseJSONValue(JSON_DATA) as TJSONObject;
try
// TryGetValue restituisce False se la chiave non è trovata (nessuna eccezione)
if LJSONObject.TryGetValue<string>('name', LName) then
WriteLn('Nome: ', LName)
else
WriteLn('Nome non trovato');
if LJSONObject.TryGetValue<Integer>('age', LAge) then
WriteLn('Età: ', LAge)
else
WriteLn('Età non trovata');
// Questa chiave non esiste - nessuna eccezione sollevata
if LJSONObject.TryGetValue<string>('middleName', LMiddleName) then
WriteLn('Secondo Nome: ', LMiddleName)
else
WriteLn('Secondo Nome: (non specificato)');
finally
LJSONObject.Free;
end;
ReadLn;
end.
Metodo 3: FindValue - Restituisce nil se Non Trovato
Quando hai bisogno di accedere all’oggetto TJSONValue grezzo piuttosto che a un valore convertito, usa FindValue. Questo metodo restituisce nil se la chiave non esiste, non solleva mai un’eccezione e ti dà pieno accesso alle proprietà e metodi del valore JSON. È utile quando devi controllare il tipo effettivo di un valore o quando lavori con strutture annidate complesse:
program JSONReadFindValue;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
const
JSON_DATA = '{"name":"Daniele","age":45}';
var
LJSONObject: TJSONObject;
LValue: TJSONValue;
begin
LJSONObject := TJSONObject.ParseJSONValue(JSON_DATA) as TJSONObject;
try
// FindValue restituisce nil se non trovato (non solleva mai eccezioni)
LValue := LJSONObject.FindValue('name');
if LValue <> nil then
WriteLn('Nome: ', LValue.Value);
LValue := LJSONObject.FindValue('nonexistent');
if LValue = nil then
WriteLn('Chiave "nonexistent" non trovata');
finally
LJSONObject.Free;
end;
ReadLn;
end.
Metodo 4: Notazione a Percorso per Valori Annidati
Una delle caratteristiche più comode di Delphi è la notazione a percorso - puoi accedere a valori profondamente annidati usando percorsi separati da punti come 'person.address.city' invece di navigare attraverso più oggetti intermedi. Questo funziona con TryGetValue, GetValue e FindValue, rendendo molto più facile estrarre valori specifici da strutture JSON complesse senza scrivere codice di navigazione verboso:
program JSONReadPath;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
const
JSON_DATA = '{' +
'"person": {' +
' "name": "Daniele",' +
' "address": {' +
' "city": "Rome",' +
' "country": "Italy"' +
' }' +
'}' +
'}';
var
LJSONObject: TJSONObject;
LValue: string;
begin
LJSONObject := TJSONObject.ParseJSONValue(JSON_DATA) as TJSONObject;
try
// Usa la notazione a punto per accedere ai valori annidati
if LJSONObject.TryGetValue<string>('person.name', LValue) then
WriteLn('Nome Persona: ', LValue);
if LJSONObject.TryGetValue<string>('person.address.city', LValue) then
WriteLn('Città: ', LValue);
if LJSONObject.TryGetValue<string>('person.address.country', LValue) then
WriteLn('Paese: ', LValue);
finally
LJSONObject.Free;
end;
ReadLn;
end.
Lettura di Array - Approcci Classico e Moderno
Quando il tuo JSON contiene array, dovrai iterare sui loro elementi per elaborare ogni valore. Delphi supporta sia i cicli tradizionali basati su indice usando Items[I] che la più moderna sintassi for-in che funziona con qualsiasi TJSONArray. L’approccio for-in è più pulito quando non hai bisogno dell’indice, mentre il ciclo classico ti dà accesso alla posizione. Per array numerici, converti ogni elemento in TJSONNumber per accedere a metodi come AsInt o AsDouble:
program JSONReadArrays;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
const
JSON_DATA = '{"skills":["Delphi","Python","SQL"],"scores":[95,87,92]}';
var
LJSONObject: TJSONObject;
LSkills: TJSONArray;
LScores: TJSONArray;
LItem: TJSONValue;
I: Integer;
begin
LJSONObject := TJSONObject.ParseJSONValue(JSON_DATA) as TJSONObject;
try
// Leggi array di stringhe - ciclo for classico
if LJSONObject.TryGetValue<TJSONArray>('skills', LSkills) then
begin
WriteLn('Competenze (ciclo classico):');
for I := 0 to LSkills.Count - 1 do
WriteLn(' ', I + 1, '. ', LSkills.Items[I].Value);
end;
WriteLn;
// Leggi array di stringhe - ciclo for-in moderno (Delphi XE+)
if LJSONObject.TryGetValue<TJSONArray>('skills', LSkills) then
begin
WriteLn('Competenze (ciclo for-in):');
for LItem in LSkills do
WriteLn(' - ', LItem.Value);
end;
WriteLn;
// Leggi array numerico
if LJSONObject.TryGetValue<TJSONArray>('scores', LScores) then
begin
WriteLn('Punteggi:');
for LItem in LScores do
WriteLn(' Punteggio: ', (LItem as TJSONNumber).AsInt);
end;
finally
LJSONObject.Free;
end;
ReadLn;
end.
Iterazione sulle Coppie di un Oggetto JSON
A volte devi elaborare tutte le proprietà in un oggetto JSON senza conoscere i nomi delle chiavi in anticipo - per esempio, quando costruisci un visualizzatore JSON generico o quando la struttura è dinamica. Il ciclo for-in funziona su TJSONObject proprio come sugli array, producendo istanze TJSONPair. Ogni coppia ti dà accesso sia alla chiave (tramite JsonString.Value) che al valore (tramite JsonValue), oltre a ispezionare il tipo runtime usando ClassName:
program JSONIteratePairs;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
const
JSON_DATA = '{"name":"Daniele","age":45,"city":"Rome","active":true}';
var
LJSONObject: TJSONObject;
LPair: TJSONPair;
begin
LJSONObject := TJSONObject.ParseJSONValue(JSON_DATA) as TJSONObject;
try
WriteLn('Tutte le coppie nell''oggetto:');
WriteLn;
// Itera su tutte le coppie usando for-in
for LPair in LJSONObject do
begin
WriteLn('Chiave: ', LPair.JsonString.Value);
WriteLn('Valore: ', LPair.JsonValue.ToString);
WriteLn('Tipo: ', LPair.JsonValue.ClassName);
WriteLn;
end;
finally
LJSONObject.Free;
end;
ReadLn;
end.
Modifica di Oggetti JSON
Gli oggetti JSON in Delphi sono completamente mutabili - puoi aggiungere, rimuovere e aggiornare proprietà dopo la creazione. Capire le regole di gestione della memoria è cruciale: quando chiami RemovePair, la proprietà di quella coppia viene trasferita a te, quindi devi liberarla. Il metodo Free in Delphi è sicuro da chiamare su nil, quindi il pattern RemovePair('key').Free funziona anche se la chiave non esiste.
Aggiunta e Rimozione di Coppie
Questo esempio dimostra il ciclo di vita completo della modifica di un oggetto JSON: creazione di proprietà iniziali, rimozione di una e aggiornamento di un’altra. Nota che per aggiornare un valore, devi prima rimuovere la vecchia coppia (liberandola) e poi aggiungerne una nuova con la stessa chiave:
program JSONModify;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
var
LJSONObject: TJSONObject;
LRemovedPair: TJSONPair;
begin
LJSONObject := TJSONObject.Create;
try
// Aggiungi coppie iniziali
LJSONObject.AddPair('name', 'Daniele');
LJSONObject.AddPair('city', 'Rome');
LJSONObject.AddPair('temp', 'da rimuovere');
WriteLn('Iniziale:');
WriteLn(LJSONObject.ToString);
WriteLn;
// Rimuovi una coppia - RemovePair restituisce la coppia rimossa (ne hai la proprietà!)
LRemovedPair := LJSONObject.RemovePair('temp');
LRemovedPair.Free; // Sicuro anche se nil - Free controlla Self <> nil
WriteLn('Dopo la rimozione di "temp":');
WriteLn(LJSONObject.ToString);
WriteLn;
// Per aggiornare un valore: rimuovi poi aggiungi
LRemovedPair := LJSONObject.RemovePair('city');
LRemovedPair.Free;
LJSONObject.AddPair('city', 'Milan');
WriteLn('Dopo l''aggiornamento di "city":');
WriteLn(LJSONObject.ToString);
finally
LJSONObject.Free;
end;
ReadLn;
end.
Output:
Iniziale:
{"name":"Daniele","city":"Rome","temp":"da rimuovere"}
Dopo la rimozione di "temp":
{"name":"Daniele","city":"Rome"}
Dopo l'aggiornamento di "city":
{"name":"Daniele","city":"Milan"}
Clonazione di Oggetti JSON
Quando hai bisogno di creare una versione modificata di un oggetto JSON senza influenzare l’originale, usa il metodo Clone. Questo crea una copia profonda - un albero di oggetti completamente indipendente dove le modifiche al clone non influenzano l’originale e viceversa. Questo è essenziale quando ricevi dati JSON che devi trasformare prima di inviare altrove preservando l’originale:
program JSONClone;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON;
var
LOriginal: TJSONObject;
LClone: TJSONObject;
LPair: TJSONPair;
begin
LOriginal := TJSONObject.Create;
try
LOriginal.AddPair('name', 'Daniele');
LOriginal.AddPair('city', 'Rome');
// Clone crea una copia indipendente
LClone := LOriginal.Clone as TJSONObject;
try
// Modifica il clone - l'originale non è influenzato
LPair := LClone.RemovePair('city');
LPair.Free;
LClone.AddPair('city', 'Milan');
WriteLn('Originale: ', LOriginal.ToString);
WriteLn('Clone: ', LClone.ToString);
finally
LClone.Free;
end;
finally
LOriginal.Free;
end;
ReadLn;
end.
Output:
Originale: {"name":"Daniele","city":"Rome"}
Clone: {"name":"Daniele","city":"Milan"}
Lavorare con File JSON
Persistere JSON su disco è un requisito comune per file di configurazione, caching ed esportazione di dati. L’unit System.IOUtils di Delphi fornisce la classe TFile con semplici metodi per leggere e scrivere file di testo, che si abbina perfettamente con la rappresentazione in stringa di JSON.
Salvare JSON su File
Per salvare un oggetto JSON su file, convertilo in una stringa usando Format() (per output leggibile) o ToString() (per output compatto), quindi scrivi quella stringa su disco. Usare TPath.GetDocumentsPath assicura che il tuo file vada in una posizione scrivibile che funziona su diverse configurazioni di Windows:
program JSONSaveToFile;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.IOUtils,
System.JSON;
var
LJSONObject: TJSONObject;
LDatabase: TJSONObject;
LFileName: string;
begin
LFileName := TPath.Combine(TPath.GetDocumentsPath, 'config.json');
LJSONObject := TJSONObject.Create;
try
LJSONObject.AddPair('appName', 'MyApplication');
LJSONObject.AddPair('version', '1.0.0');
LJSONObject.AddPair('debug', False);
LDatabase := TJSONObject.Create;
LJSONObject.AddPair('database', LDatabase);
LDatabase.AddPair('host', 'localhost');
LDatabase.AddPair('port', 5432);
// Salva su file
{$IF CompilerVersion >= 33.0}
TFile.WriteAllText(LFileName, LJSONObject.Format());
{$ELSE}
TFile.WriteAllText(LFileName, LJSONObject.ToString);
{$ENDIF}
WriteLn('Salvato in: ', LFileName);
finally
LJSONObject.Free;
end;
ReadLn;
end.
Caricamento di JSON da File
Leggere JSON da un file è altrettanto semplice: leggi il contenuto del file in una stringa, quindi analizzalo con ParseJSONValue. Controlla sempre prima se il file esiste per evitare eccezioni e verifica che il parsing sia riuscito prima di accedere ai dati. La notazione a percorso funziona altrettanto bene su JSON analizzato quanto su oggetti costruiti manualmente:
program JSONLoadFromFile;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.IOUtils,
System.JSON;
var
LJSONObject: TJSONObject;
LJSONValue: TJSONValue;
LContent: string;
LFileName: string;
LAppName: string;
LPort: Integer;
begin
LFileName := TPath.Combine(TPath.GetDocumentsPath, 'config.json');
if not TFile.Exists(LFileName) then
begin
WriteLn('File non trovato: ', LFileName);
ReadLn;
Exit;
end;
LContent := TFile.ReadAllText(LFileName);
LJSONValue := TJSONObject.ParseJSONValue(LContent);
if LJSONValue = nil then
begin
WriteLn('JSON non valido nel file!');
ReadLn;
Exit;
end;
try
LJSONObject := LJSONValue as TJSONObject;
if LJSONObject.TryGetValue<string>('appName', LAppName) then
WriteLn('Nome App: ', LAppName);
if LJSONObject.TryGetValue<Integer>('database.port', LPort) then
WriteLn('Porta Database: ', LPort);
finally
LJSONValue.Free;
end;
ReadLn;
end.
Esempio Pratico: Client REST API
Ora mettiamo tutto insieme in uno scenario del mondo reale: chiamare una REST API ed elaborare la risposta JSON. Questo esempio si connette a JSONPlaceholder (una API di test gratuita), recupera una lista di utenti e analizza ognuno in un record Delphi. Nota come usiamo TryGetValue ovunque per gestire con eleganza i campi potenzialmente mancanti - un must quando si ha a che fare con API esterne che potrebbero cambiare.
THTTPClient richiede Delphi XE8 o successivo.
program JSONRestApiClient;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.JSON,
System.Net.HttpClient; // Richiede Delphi XE8+
type
TUser = record
ID: Integer;
Name: string;
Email: string;
Username: string;
end;
function ParseUser(AJSONObject: TJSONObject): TUser;
begin
// Uso di TryGetValue per sicurezza
if not AJSONObject.TryGetValue<Integer>('id', Result.ID) then
Result.ID := 0;
if not AJSONObject.TryGetValue<string>('name', Result.Name) then
Result.Name := '';
if not AJSONObject.TryGetValue<string>('email', Result.Email) then
Result.Email := '';
if not AJSONObject.TryGetValue<string>('username', Result.Username) then
Result.Username := '';
end;
var
LClient: THTTPClient;
LResponse: IHTTPResponse;
LJSONValue: TJSONValue;
LJSONArray: TJSONArray;
LUserJSON: TJSONObject;
LUser: TUser;
I: Integer;
begin
WriteLn('Recupero utenti dall''API JSONPlaceholder...');
WriteLn;
LClient := THTTPClient.Create;
try
LResponse := LClient.Get('https://jsonplaceholder.typicode.com/users');
if LResponse.StatusCode <> 200 then
begin
WriteLn('Errore HTTP: ', LResponse.StatusCode);
ReadLn;
Exit;
end;
// Analizza la risposta array JSON
LJSONValue := TJSONObject.ParseJSONValue(LResponse.ContentAsString);
if LJSONValue = nil then
begin
WriteLn('Risposta JSON non valida');
ReadLn;
Exit;
end;
try
if not (LJSONValue is TJSONArray) then
begin
WriteLn('Atteso array JSON');
Exit;
end;
LJSONArray := LJSONValue as TJSONArray;
WriteLn('Trovati ', LJSONArray.Count, ' utenti:');
WriteLn(StringOfChar('-', 50));
for I := 0 to LJSONArray.Count - 1 do
begin
LUserJSON := LJSONArray.Items[I] as TJSONObject;
LUser := ParseUser(LUserJSON);
WriteLn('ID: ', LUser.ID);
WriteLn('Nome: ', LUser.Name);
WriteLn('Email: ', LUser.Email);
WriteLn('Username: ', LUser.Username);
WriteLn(StringOfChar('-', 50));
end;
finally
LJSONValue.Free;
end;
finally
LClient.Free;
end;
ReadLn;
end.
Esempio Pratico: Gestore File di Configurazione
Questo esempio finale mostra una classe completa e riutilizzabile per gestire la configurazione dell’applicazione. Il TConfigManager incapsula tutta la complessità di caricamento, salvataggio e accesso alle impostazioni fornendo una API pulita e type-safe. Dimostra il caricamento lazy (legge il file solo quando necessario), valori predefiniti per chiavi mancanti e creazione automatica del file. Puoi usare questo pattern come punto di partenza per i tuoi sistemi di configurazione:
program JSONConfigManager;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.IOUtils,
System.JSON;
type
TConfigManager = class
private
FFileName: string;
FJSONObject: TJSONObject;
FModified: Boolean;
procedure EnsureLoaded;
public
constructor Create(const AFileName: string);
destructor Destroy; override;
procedure Load;
procedure Save;
function GetString(const AKey: string; const ADefault: string = ''): string;
function GetInteger(const AKey: string; const ADefault: Integer = 0): Integer;
function GetBoolean(const AKey: string; const ADefault: Boolean = False): Boolean;
procedure SetValue(const AKey: string; const AValue: string); overload;
procedure SetValue(const AKey: string; const AValue: Integer); overload;
procedure SetValue(const AKey: string; const AValue: Boolean); overload;
property FileName: string read FFileName;
property Modified: Boolean read FModified;
end;
constructor TConfigManager.Create(const AFileName: string);
begin
inherited Create;
FFileName := AFileName;
FJSONObject := nil;
FModified := False;
end;
destructor TConfigManager.Destroy;
begin
FJSONObject.Free;
inherited;
end;
procedure TConfigManager.EnsureLoaded;
begin
if FJSONObject = nil then
Load;
end;
procedure TConfigManager.Load;
var
LContent: string;
LJSONValue: TJSONValue;
begin
FreeAndNil(FJSONObject);
FModified := False;
if TFile.Exists(FFileName) then
begin
LContent := TFile.ReadAllText(FFileName);
LJSONValue := TJSONObject.ParseJSONValue(LContent);
if (LJSONValue <> nil) and (LJSONValue is TJSONObject) then
FJSONObject := TJSONObject(LJSONValue)
else if LJSONValue <> nil then
LJSONValue.Free;
end;
if FJSONObject = nil then
FJSONObject := TJSONObject.Create;
end;
procedure TConfigManager.Save;
begin
EnsureLoaded;
{$IF CompilerVersion >= 33.0}
TFile.WriteAllText(FFileName, FJSONObject.Format());
{$ELSE}
TFile.WriteAllText(FFileName, FJSONObject.ToString);
{$ENDIF}
FModified := False;
end;
function TConfigManager.GetString(const AKey, ADefault: string): string;
begin
EnsureLoaded;
if not FJSONObject.TryGetValue<string>(AKey, Result) then
Result := ADefault;
end;
function TConfigManager.GetInteger(const AKey: string; const ADefault: Integer): Integer;
begin
EnsureLoaded;
if not FJSONObject.TryGetValue<Integer>(AKey, Result) then
Result := ADefault;
end;
function TConfigManager.GetBoolean(const AKey: string; const ADefault: Boolean): Boolean;
begin
EnsureLoaded;
if not FJSONObject.TryGetValue<Boolean>(AKey, Result) then
Result := ADefault;
end;
procedure TConfigManager.SetValue(const AKey: string; const AValue: string);
begin
EnsureLoaded;
FJSONObject.RemovePair(AKey).Free;
FJSONObject.AddPair(AKey, AValue);
FModified := True;
end;
procedure TConfigManager.SetValue(const AKey: string; const AValue: Integer);
begin
EnsureLoaded;
FJSONObject.RemovePair(AKey).Free;
FJSONObject.AddPair(AKey, AValue);
FModified := True;
end;
procedure TConfigManager.SetValue(const AKey: string; const AValue: Boolean);
begin
EnsureLoaded;
FJSONObject.RemovePair(AKey).Free;
FJSONObject.AddPair(AKey, AValue);
FModified := True;
end;
// Dimostrazione di utilizzo
var
Config: TConfigManager;
LConfigFile: string;
begin
LConfigFile := TPath.Combine(TPath.GetDocumentsPath, 'appsettings.json');
WriteLn('File di configurazione: ', LConfigFile);
WriteLn;
Config := TConfigManager.Create(LConfigFile);
try
// Imposta alcuni valori (le chiavi sono piatte - non oggetti annidati)
Config.SetValue('databaseHost', 'localhost');
Config.SetValue('databasePort', 5432);
Config.SetValue('databaseName', 'myapp');
Config.SetValue('loggingEnabled', True);
Config.SetValue('loggingMaxFiles', 10);
Config.Save;
WriteLn('Configurazione salvata!');
WriteLn;
// Rileggi i valori
WriteLn('Host Database: ', Config.GetString('databaseHost'));
WriteLn('Porta Database: ', Config.GetInteger('databasePort'));
WriteLn('Logging Abilitato: ', Config.GetBoolean('loggingEnabled'));
// Leggi con valore predefinito
WriteLn('Timeout (predefinito 30): ', Config.GetInteger('timeout', 30));
finally
Config.Free;
end;
ReadLn;
end.
Output:
File di configurazione: C:\Users\yourname\Documents\appsettings.json
Configurazione salvata!
Host Database: localhost
Porta Database: 5432
Logging Abilitato: TRUE
Timeout (predefinito 30): 30
Librerie JSON di Terze Parti
Sebbene il parser JSON integrato di Delphi sia eccellente per la maggior parte dei casi d’uso, alcuni scenari possono beneficiare di librerie di terze parti:
| Libreria | Migliore Per | URL |
|---|---|---|
| JsonDataObjects | Alte prestazioni, usata da DelphiMVCFramework | GitHub |
| Grijjy Foundation | Ricca di funzionalità, include supporto BSON | GitHub |
| mORMot2 | Livello enterprise, molto veloce | GitHub |
Quando Usare Librerie di Terze Parti
- File JSON grandi (>10MB): Considera parser streaming o JsonDataObjects
- Parsing ad alta frequenza: JsonDataObjects o mORMot2 offrono prestazioni migliori
- Necessità supporto BSON: Grijjy Foundation
- Serializzazione oggetti: Serializzatori di DelphiMVCFramework o mORMot2
Per la maggior parte delle applicazioni, il System.JSON integrato è sufficiente e ha il vantaggio di non avere dipendenze esterne.
Costruire REST API con JSON
Se stai costruendo REST API in Delphi, DelphiMVCFramework fornisce eccellente supporto JSON con serializzazione automatica:
[MVCPath('/api/customers')]
TCustomersController = class(TMVCController)
public
[MVCPath]
[MVCHTTPMethod([httpGET])]
procedure GetCustomers;
[MVCPath('/($id)')]
[MVCHTTPMethod([httpGET])]
procedure GetCustomer(id: Integer);
end;
procedure TCustomersController.GetCustomers;
var
LCustomers: TObjectList<TCustomer>;
begin
LCustomers := TCustomerService.GetAll;
Render(LCustomers); // Serializzazione JSON automatica
end;
Vedi gli esempi di DelphiMVCFramework per esempi completi.
Domande Frequenti (FAQ)
Come faccio a fare il parsing di una stringa JSON in Delphi?
Usa TJSONObject.ParseJSONValue() dall’unit System.JSON:
uses System.JSON;
var
LJSONObject: TJSONObject;
LValue: TJSONValue;
begin
LValue := TJSONObject.ParseJSONValue('{"name":"John"}');
if (LValue <> nil) and (LValue is TJSONObject) then
begin
LJSONObject := TJSONObject(LValue);
try
WriteLn(LJSONObject.GetValue<string>('name')); // Output: John
finally
LJSONObject.Free;
end;
end;
end;
Come gestisco i valori null in JSON?
Usa TryGetValue per gestire in sicurezza valori mancanti o null:
var
LValue: string;
begin
if LJSONObject.TryGetValue<string>('optionalField', LValue) then
WriteLn('Valore: ', LValue)
else
WriteLn('Campo mancante o null');
end;
Come itero su un array JSON?
Usa la sintassi moderna del ciclo for-in:
var
LArray: TJSONArray;
LItem: TJSONValue;
begin
if LJSONObject.TryGetValue<TJSONArray>('items', LArray) then
begin
for LItem in LArray do
WriteLn(LItem.Value);
end;
end;
Qual è la differenza tra Format() e ToString()?
Format(): Restituisce JSON indentato e leggibile (Solo Delphi 10.3+)ToString(): Restituisce JSON compatto senza spazi (meglio per il trasferimento di rete, funziona in tutte le versioni)
Come modifico un oggetto JSON esistente?
Usa RemovePair poi AddPair. RemovePair restituisce la coppia rimossa (o nil se non trovata) - ne hai la proprietà e devi liberarla:
begin
// Remove restituisce la coppia - devi liberarla!
// Free è sicuro da chiamare su nil (controlla internamente Self <> nil)
LJSONObject.RemovePair('name').Free;
// Aggiungi nuovo valore
LJSONObject.AddPair('name', 'Nuovo Valore');
end;
Quale versione di Delphi ha introdotto il supporto JSON?
- Delphi 2009: Supporto JSON iniziale nell’unit
DBXJSON - Delphi XE6: Rinominata in
System.JSONcon miglioramenti API - Delphi 10.1 Berlin: API fluent
TJSONObjectBuilder - Delphi 10.3 Rio: Aggiunto metodo
Format(),EJSONParseExceptioncon informazioni dettagliate sull’errore
Qual è la differenza tra GetValue, FindValue e TryGetValue?
| Metodo | Restituisce | Se Chiave Non Trovata |
|---|---|---|
GetValue<T>('key') |
Valore di tipo T | Solleva eccezione |
FindValue('key') |
TJSONValue o nil | Restituisce nil |
TryGetValue<T>('key', outVar) |
Boolean | Restituisce False |
Raccomandazione: Usa TryGetValue per il codice di produzione in quanto è l’approccio più sicuro.
Come creo una copia profonda di un oggetto JSON?
Usa il metodo Clone:
var
LOriginal, LCopy: TJSONObject;
begin
LOriginal := TJSONObject.ParseJSONValue('{"name":"test"}') as TJSONObject;
try
LCopy := LOriginal.Clone as TJSONObject;
try
// LCopy è indipendente - le modifiche non influenzano LOriginal
finally
LCopy.Free;
end;
finally
LOriginal.Free;
end;
end;
Come controllo se un valore JSON è null?
var
LValue: TJSONValue;
begin
LValue := LJSONObject.FindValue('myField');
if LValue = nil then
WriteLn('Il campo non esiste')
else if LValue is TJSONNull then
WriteLn('Il campo esiste ma è null')
else
WriteLn('Il campo ha un valore: ', LValue.Value);
end;
Posso usare la notazione a percorso per accedere agli elementi di un array?
Sì, usa la notazione tra parentesi quadre con l’indice:
var
LFirstSkill: string;
begin
// Accedi al primo elemento dell'array skills
if LJSONObject.TryGetValue<string>('skills[0]', LFirstSkill) then
WriteLn('Prima competenza: ', LFirstSkill);
end;
Come converto un oggetto Delphi in JSON?
Per casi semplici, costruisci il JSON manualmente con TJSONObject. Per la serializzazione automatica di oggetti e record, usa i serializzatori di DelphiMVCFramework o librerie di terze parti come mORMot2. Questi possono convertire qualsiasi oggetto Delphi in JSON con una singola chiamata di metodo.
System.JSON è thread-safe?
No, TJSONObject e le classi correlate non sono thread-safe. Se più thread devono accedere allo stesso oggetto JSON, devi implementare la tua sincronizzazione (sezioni critiche, lock, ecc.). Per l’accesso in sola lettura dopo il parsing iniziale, puoi condividere in sicurezza l’oggetto tra i thread finché non avvengono modifiche.
Come serializzo un TDateTime in JSON?
TJSONObject non ha un overload integrato di AddPair per TDateTime. Convertilo prima in una stringa usando un formato standard come ISO 8601:
LJSONObject.AddPair('createdAt', FormatDateTime('yyyy-mm-dd"T"hh:nn:ss', Now));
Qual è la dimensione massima di JSON che Delphi può analizzare?
Non c’è un limite rigido, ma System.JSON carica l’intero documento in memoria. Per file molto grandi (>100MB), considera parser streaming come TJsonTextReader da System.JSON.Readers, o librerie di terze parti ottimizzate per documenti grandi.
Qual è la differenza tra System.JSON e DBXJSON?
Sono la stessa libreria - solo rinominata. DBXJSON era il nome originale dell’unit in Delphi 2009-XE5. A partire da Delphi XE6, è stata rinominata in System.JSON per seguire le nuove convenzioni di denominazione. L’API è essenzialmente la stessa, quindi migrare il vecchio codice è semplice.
Come faccio a formattare in modo leggibile (pretty print) JSON in Delphi?
Usa il metodo Format() (Delphi 10.3+) che restituisce JSON indentato e leggibile:
WriteLn(LJSONObject.Format()); // Formattato con indentazione
WriteLn(LJSONObject.ToString); // Compatto, singola riga
Per le versioni più vecchie di Delphi, usa librerie di terze parti o implementa una formattazione personalizzata.
Come gestisco i caratteri speciali e Unicode in JSON?
System.JSON gestisce automaticamente Unicode ed effettua l’escape dei caratteri speciali quando genera JSON. Durante il parsing, le sequenze di escape come \n, \t e \uXXXX vengono correttamente convertite. Non è necessaria gestione manuale:
LJSONObject.AddPair('message', 'Riga 1'#13#10'Riga 2'); // Newline con escape automatico
LJSONObject.AddPair('emoji', '🚀'); // Unicode funziona direttamente
Come unisco due oggetti JSON?
Non c’è una funzione di merge integrata. Itera su un oggetto e aggiungi le sue coppie all’altro:
for LPair in LSource do
LTarget.AddPair(LPair.JsonString.Value, LPair.JsonValue.Clone as TJSONValue);
Nota: Devi clonare i valori poiché possono appartenere solo a un oggetto genitore.
Come valido JSON prima del parsing?
ParseJSONValue restituisce nil per JSON non valido, che serve come validazione base. Per la validazione dello schema (controllo struttura, campi obbligatori, tipi), avrai bisogno di librerie di terze parti poiché Delphi non include supporto integrato per JSON Schema.
Come accedo ad array profondamente annidati?
Combina la notazione a percorso con l’indicizzazione dell’array:
// Accedi a: {"data": {"users": [{"name": "Alice"}, {"name": "Bob"}]}}
if LJSONObject.TryGetValue<string>('data.users[1].name', LValue) then
WriteLn(LValue); // Output: Bob
Posso usare JSON con i dataset FireDAC?
Sì, ma non c’è integrazione diretta. Puoi iterare manualmente su un dataset e costruire JSON, o usare librerie di serializzazione. Sia DelphiMVCFramework che mORMot2 forniscono serializzazione dataset-to-JSON pronta all’uso.
Come gestisco JSON con chiavi duplicate?
JSON tecnicamente permette chiavi duplicate, anche se è sconsigliato. TJSONObject memorizza tutte le coppie, ma GetValue/TryGetValue restituiscono solo la prima corrispondenza. Per accedere a tutti i valori con la stessa chiave, itera usando il ciclo for-in.
Riepilogo
Delphi fornisce un supporto JSON robusto e integrato tramite l’unit System.JSON. Punti chiave:
- Usa
TJSONObjecteTJSONArrayper creare e analizzare JSON - Controlla sempre nil quando analizzi stringhe JSON
- Usa
TryGetValueper la lettura sicura dei valori con campi opzionali - Usa la notazione a percorso (
'parent.child') per valori annidati - Ricorda la gestione della memoria: gli oggetti genitori possiedono i loro figli;
RemovePairrestituisce la proprietà a te - Considera librerie di terze parti solo per esigenze specifiche di prestazioni
- Usa
Format()per output leggibile (Delphi 10.3+),ToString()per output compatto - Usa cicli for-in per iterazione più pulita su array e coppie di oggetti
Per costruire moderne REST API in Delphi, dai un’occhiata a DelphiMVCFramework - include serializzazione JSON avanzata ed è usato in produzione da aziende in tutto il mondo.
Comments
comments powered by Disqus