JSON e XML
Ler, navegar e escrever JSON sem exceções para o que falta, e o módulo de XML.
JSON#
O System.Json foi escrito para o caso que mais aperta: consumir a resposta de uma API de terceiro, que sempre manda o que não devia, como um campo ausente, um nulo onde se esperava número, um número onde se esperava texto, ou um objeto onde se esperava uma lista. Por isso a navegação não levanta exceção: Find, Item e Path devolvem nil, e os conversores têm valor padrão. Quem quiser rigor pede explicitamente (Member levanta; TryAs… informa).
program JsonDemo;
uses
System.Json;
var
Doc, Tag, Root: TJsonValue;
begin
// navegação defensiva: Find, Item e Path devolvem nil, nunca levantam exceção
Doc := TJsonValue.Parse(
'{"id": 42, "name": "Ana", "price": 19.99, ' +
'"tags": ["a", "b"], "address": {"city": "Recife"}}');
try
WriteLn('id: ', Doc.Int64Of('id'));
WriteLn('name: ', Doc.TextOf('name'));
// o número não passa por ponto flutuante: preço exato
WriteLn('price*3: ', Doc.CurrencyOf('price') * 3);
WriteLn('cidade: ', Doc.PathText('address/city'));
WriteLn('cep: ', Doc.PathText('address/zip', 'sem CEP'));
Tag := Doc.Find('tags').First;
while Tag <> nil do
begin
WriteLn('tag: ', Tag.AsText);
Tag := Tag.Next;
end while;
finally
Doc.Dispose;
end try;
// construção: Put* num objeto, Add* numa lista
Root := TJsonValue.NewObject;
try
Root.PutText('hello', 'mundo');
Root.PutInt('n', 3);
Root.PutArray('list').AddInt(1);
WriteLn(Root.ToUString);
finally
Root.Dispose;
end try;
end.id: 42
name: Ana
price*3: 59.9700
cidade: Recife
cep: sem CEP
tag: a
tag: b
{"hello":"mundo","n":3,"list":[1]}Números exatos#
O número não passa por ponto flutuante. O literal é guardado como veio e só é convertido quando alguém pede, em Int64 ou em Currency64 (ponto fixo). Um preço de marketplace vira dinheiro exato (19.99), não 19.989999….
Um mapa do TJsonValue#
| Grupo | Membros |
|---|---|
| Ler | TJsonValue.Parse(texto), TryParse(texto, valor, erro), ParseUtf8 |
| Forma | IsNull, IsBool, IsNumber, IsText, IsArray, IsObject, Count |
Navegar (devolvem nil) | Find(nome), Item(índice), Path('a/b/0/c'), First, Next |
| Atalhos por nome | TextOf, Int64Of, CurrencyOf, BoolOf (todos com padrão) |
| Atalhos por caminho | PathText, PathInt64, PathCurrency (atravessam o nil) |
| Converter | AsText, AsInt64, AsCurrency, AsBool (com padrão); TryAsInt64, TryAsCurrency |
| Construir | NewObject, NewArray, Put… (em objeto) e Add… (em lista) |
| Escrever | ToUString, ToUtf8, WriteTo |
| Rigor | Member(nome) levanta EJsonMemberNotFound; CheckKind levanta EJsonKindMismatch |
Path separa por barra: um segmento todo numérico indexa uma lista, e o resto procura um membro de objeto.
Memória#
O objeto nasce com +1 e a cadeia do pai retém outro +1. Quem recebe a raiz (de Parse ou de uma fábrica New…) é dono dela e a destrói com Dispose. O que Add…/Put… devolve é emprestado: pertence ao pai, não se solta. A profundidade máxima de aninhamento é limitada (200), para que uma entrada hostil não derrube a pilha.
XML#
O System.Xml traz um modelo de documento XML, com texto em UString. Está disponível nas duas RTLs.