Utilização das funções JSON
O FileMaker Pro fornece várias funções de texto que permitem que seu app personalizado analise e modifique dados JSON de outras fontes ou outras funções do FileMaker, como serviços da Web que transferem dados no formato JSON por meio de uma API REST.
Para mais informações sobre o formato de dados JSON, consulte json.org.
Os exemplos mostrados neste tópico usam dados JSON de uma padaria que disponibiliza sua lista de produtos para clientes no formato JSON por meio de uma API REST. A fórmula a seguir retorna os produtos promocionais do dia como dados JSON na variável $$JSON:
Definir variável [ $url ; "https://bakery.example.com/rest/api/products" ]
Inserir do URL [ Com diálogo: Desativado; Destino: $$JSON ; $url ; Verificar certificados SSL ; opções cURL: "--data list=specials" ]
Para os dados retornados em $$JSON e usados nesses exemplos, consulte Exemplo de dados JSON.
Formatação de dados JSON
Os dados JSON não exigem espaços ou terminações de linha entre os elementos. No entanto, para facilitar a leitura dos dados ao depurar problemas, use a Função JSONFormatElements, que adiciona caracteres de tabulação e de terminação de linha, conforme mostrado em Exemplo de dados JSON.
Análise de dados JSON
Use as seguintes funções JSON ao analisar dados JSON, ou seja, para obter chaves, valores ou matrizes ou objetos JSON completos que você pode processar ainda mais:
-
JSONGetElement – Consulta dados JSON em busca de um elemento (objeto, matriz ou valor)
-
JSONListKeys – Lista nomes de objeto (chaves) ou índices de matriz em dados JSON
-
JSONListValues – Lista valores em dados JSON
O primeiro parâmetro dessas funções, json
, especifica o campo de texto, a variável ou a expressão do texto que contém dados JSON válidos para operação.
O segundo parâmetro, chaveOuÍndiceOuCaminho
, especifica a parte dos dados JSON para operação:
-
chave – o nome de uma chave em um objeto JSON
-
índice – o índice de um elemento em uma matriz JSON (o primeiro elemento possui um índice de 0)
-
caminho – uma string hierárquica de nomes de chave, índices de matriz ou ambos
Os dois tipos a seguir de sintaxe para o parâmetro chaveOuÍndiceOuCaminho
são compatíveis: notação de pontos e notação de colchetes.
Sintaxe para o parâmetro |
Significa |
|
Notação de pontos | Notação de colchetes | |
---|---|---|
|
|
O nível raiz, se for o primeiro caractere (opcional na notação de pontos) |
|
|
Elementos no índice n de uma matriz no nível raiz |
|
|
A chave de um objeto chamado nome no nível raiz |
|
|
Um objeto chamado nomeC, que é descendente de nomeB e nomeA |
|
|
O primeiro elemento da matriz no objeto nomeA, que está no terceiro nível em um conjunto de matrizes aninhadas |
|
|
O último elemento de uma matriz |
|
|
A posição após o último elemento de uma matriz. Use a Função JSONSetElement para adicionar um elemento ao final de uma matriz. |
A diferença entre a notação de ponto e colchetes é que, em vez de usar pontos (.
) para separar nomes de chaves, a notação entre colchetes envolve nomes de chaves com aspas simples ('
) e colchetes ([]
). Você pode usar as duas notações em chaveOuÍndiceOuCaminho
. No entanto, será necessário usar a notação de colchetes se os nomes de chave incluírem pontos para que o analisador JSON possa identificar corretamente os nomes completos. Por exemplo, o nome de uma chave na raiz de um objeto JSON for "layout.response", então o
chaveOuÍndiceOuCaminho
precisará ser "['layout.response']".
O script de exemplo a seguir cria um registro para cada produto em uma matriz JSON. Supondo que os Exemplo de dados JSON estejam armazenados na variável $$JSON, o script usa JSONListValues para obter o conteúdo da matriz de produtos como uma lista de valores e usa ValueCount para determinar o número de produtos na lista. Criando um registro para um produto a cada vez no loop, o script usa GetValue para obter o objeto JSON para um produto da lista e define os campos para os valores obtidos usando JSONGetElement. Como as funções JSON analisam todo o objeto JSON passado para elas, talvez seja mais eficiente usar as funções JSON em objetos JSON menores dentro de um loop que é repetido muitas vezes.
Definir variável [ $ProductList ; Valor: JSONListValues ( $$JSON ; "padaria.produto" ) ]
Definir variável [ $ProductCount ; Valor: ValueCount ( $ProductList ) ]
Definir variável [ $i; Valor: 1 ]
If [ $ProductCount > 0 ]
Loop [ Liberar: Sempre ]
Novo registro/solicitação
Definir variável [ $Product ; Valor: GetValue ( $ProductList ; $i ) ]
Definir campo [ Produtos::ID ; JSONGetElement ( $Product ; "id" ) ]
Definir campo [ Produtos::Preço ; JSONGetElement ( $Product ; "preço" ) ]
Definir campo [ Produtos::Estoque ; JSONGetElement ( $Product ; "estoque" ) ]
Confirmar registros/solicitações [ Com diálogo: Desativado ]
Definir variável [ $i ; Valor: $i + 1 ]
Exit Loop If [ $i > $ProductCount ]
End Loop
End If
Alteração e adição de elementos em dados JSON
Para alterar valores e adicionar elementos em dados JSON, use a Função JSONSetElement. Os parâmetros json
e chaveOuÍndiceOuCaminho
funcionam nessa função conforme descrito em Análise de dados JSON. Se chaveOuÍndiceOuCaminho
especificar um elemento existente, o valor desse elemento será alterado. Se o elemento não existir, um novo elemento será adicionado.
JSONSetElement configura o elemento especificado com o parâmetro valor.
Você pode especificar qualquer valor JSON válido, de uma string ou um número simples a uma matriz ou um objeto complexo.
O parâmetro tipo
especifica o tipo de dados em valor
, de forma que o analisador JSON vai seguir regras estritas ao lidar com cada tipo de dados. Para os tipos de dados compatíveis, consulte a Função JSONSetElement. Para inserir dados em json
que já estejam formatados como um elemento JSON válido, defina type
como JSONRaw
.
O exemplo a seguir adiciona os pares de chave-calor de um novo produto em um objeto JSON vazio. Em seguida, o novo objeto é adicionado ao final da matriz de produtos na variável $$JSON (consulte Exemplo de dados JSON).
Definir variável [ $NewProduct ; Valor:
JSONSetElement ( "{}" ;
[ "id" ; "FB4" ; JSONString ] ;
[ "nome" ; "Bolo de baunilha" ; JSONString ] ;
[ "preço" ; 17.5 ; JSONNumber ] ;
[ "stock" ; 12 ; JSONNumber ] ;
[ "categoria" ; "Bolos" ; JSONString ] ;
[ "desconto" ; true ; JSONBoolean ]
) ]
Definir variável [ $NextIndex ; Valor:
ValueCount (
JSONListKeys ( $$JSON ; "padaria.produto" )
) ]
Definir variável [ $$JSON ; Valor:
JSONSetElement (
$$JSON ; "padaria.produto[" & $NextIndex & "]" ; $NewProduct ;
JSONObject
) ]
Outra função JSON que cria um elemento JSON é a função Função JSONMakeArray. Ele converte uma lista de valores em uma matriz JSON. Para aceitar dados formatados de maneiras diferentes, esta função permite que você especifique o caractere que separa cada valor e o tipo de dados JSON a ser usado.
Exclusão de elementos em dados JSON
Para excluir um elemento.use a Função JSONDeleteElement. Os parâmetros json
e chaveOuÍndiceOuCaminho
funcionam nessa função conforme descrito em Análise de dados JSON. O parâmetro chaveOuÍndiceOuCaminho
deve especificar um elemento existente em json
.
O exemplo a seguir exclui o elemento em uma matriz de produtos cuja chave "id" possui o valor "FB3" na variável $$JSON (consulte Exemplo de dados JSON).
Definir variável [ $ProductCount ; Valor:
ValueCount (
JSONListKeys ( $$JSON ; "padaria.produto" )
) ]
Definir variável [ $i ; Valor: 0 ]
If [ $ProductCount > 0 ]
Loop [ Liberar: Always ]
Definir variável [ $ID ; Valor:
JSONGetElement ( $$JSON ; "padaria.produto[" & $i & "]id" ) ]
If [ $ID = "FB3" ]
Definir variável [ $$JSON ; Valor:
JSONDeleteElement ( $$JSON ; "padaria.produto[" & $i & "]" ) ]
Sair do script [ Resultado do texto: 0 ]
End If
Definir variável [ $i ; Valor: $i + 1 ]
Exit Loop If [ $i ≥ $ProductCount ]
End Loop
End If
Otimização do desempenho do JSON
Sempre que uma função JSON analisa a entrada de texto, o analisador JSON cria uma representação binária (não texto) dela para agilizar o processamento posterior do JSON. Há um mecanismo automático para analisar e armazenar em cache JSON e um mecanismo explícito: a Função JSONParse.
Aproveitamento do cache JSON automático
A análise leva tempo, então as funções JSON armazenam em cache a representação binária do último JSON analisado na memória. Isso reduz a necessidade de analisar o mesmo JSON novamente mais tarde. Apenas um cache automático é mantido. Quando um valor JSON diferente é analisado, o valor JSON previamente armazenado em cache é descartado. O JSON analisado existe apenas na memória: em variáveis, parâmetros de script e cálculos. Quando usado para definir o valor de um campo, ele é armazenado no campo como texto.
Por número de linha, este exemplo ilustra quando o texto JSON inicialmente armazenado em $JSON1 e $JSON2 é analisado e quando não é.
Definir variável [ $id ; JSONGetElement ( $JSON1 ; "id" ) ]
Definir variável [ $name ; JSONGetElement ( $JSON1 ; "nome" ) ]
Definir variável [ $price ; JSONGetElement ( $JSON2 ; "preço" ) ]
Definir variável [ $category ; JSONGetElement ( $JSON1 ; "categoria" ) ]
-
$JSON1 é analisado e a representação binária é salva no cache.
-
$JSON1 não precisa ser analisado novamente.
-
$JSON2 é analisado e armazenado em cache, substituindo o valor armazenado anteriormente em cache.
-
$JSON1 é analisado novamente porque não estava mais armazenado em cache.
Portanto, para aproveitar o cache automático, é melhor trabalhar com um valor JSON de cada vez (no exemplo acima, troque as linhas 3 e 4 para evitar analisar $JSON1 novamente).
Uso de JSONParse
Para analisar e armazenar explicitamente a representação binária de um valor JSON em uma variável, bem como no cache automático, use a Função JSONParse. O parâmetro json
da função é qualquer expressão do texto que avalia dados JSON, seja texto formatado como JSON em um campo ou uma string, ou JSON já analisado em uma variável.
O exemplo a seguir analisa o texto JSON:
Definir variável [ $JSON1 ; "{ \"produto\": {\"id\": \"FB1\"} }" ]
Definir variável [ $JSON1 ; JSONParse ( $JSON1 ) ]
-
$JSON1 é apenas a representação de texto, que se parece com isso:
{ "produto": {"id": "FB1"} }
-
Depois de usar JSONParse:
-
O cache automático contém a representação binária.
-
A variável $JSON1 contém tanto o texto quanto as representações binárias.
-
Se JSONParse não for usado, então neste exemplo:
Definir variável [ $JSON1 ; "{ \"produto\": {\"id\": \"FB1\"} }" ]
Definir variável [ $JSON2 ; JSONGetElement ( $JSON1 ; "produto") ]
-
$JSON1 é apenas a representação de texto, como antes.
-
Depois de usar JSONGetElement:
-
O cache automático contém a representação binária.
-
$JSON2 contém a representação binária de
{"id": "FB1"}
. -
$JSON1 ainda é apenas a representação de texto. O texto foi analisado, mas a representação binária está apenas no cache automático.
-
Compare isso com o que acontece ao adicionar JSONParse:
Definir variável [ $JSON1 ; "{ \"produto\": {\"id\": \"FB1\"} }" ]
Definir variável [ $JSON1 ; JSONParse ( $JSON1 ) ]
Definir variável [ $JSON2 ; JSONGetElement ( $JSON1 ; "produto") ]
-
$JSON1 é apenas a representação de texto, como antes.
-
Depois de usar JSONParse:
-
O cache automático contém a representação binária.
-
$JSON1 contém tanto o texto quanto as representações binárias.
-
-
Depois de usar JSONGetElement:
-
$JSON2 contém a representação binária de
{"id": "FB1"}
.A representação de texto não é armazenada em $JSON2 nesse momento, mas é gerada posteriormente somente quando necessário.
-
Observe que o JSONGetElement não precisava analisar $JSON1 na linha 3, porque poderia usar a representação binária armazenada em cache com $JSON1 na linha 2.
Analisar texto para obter uma representação binária leva tempo, assim como converter JSON binário em texto. Por isso, o resultado de funções JSON como JSONGetElement e JSONSetElement é apenas a representação binária. A representação de texto é criada apenas quando necessário, como ao armazenar uma variável (como $JSON2) em um campo ou visualizar uma variável no Visualizador de dados.
Você pode usar a função complementar JSONParsedState para descobrir se um determinado valor JSON tem um JSON analisado armazenado com ele, se o JSON é válido e qual é o tipo.
Melhores práticas
Ao processar repetidamente grandes estruturas JSON (especialmente em loops) ou trabalhar com vários elementos em dados JSON, a ordem das operações pode gerar uma diferença significativa no desempenho.
Para aproveitar o cache JSON automático, é melhor não alternar entre carregar dados JSON de um campo para trabalhar, mudar para um campo diferente para trabalhar e depois voltar para o primeiro campo. Cada vez que uma função JSON processa texto JSON diferente, o JSON previamente armazenado em cache é descartado, e o texto precisa ser analisado novamente. Por exemplo, isso causa um desempenho mais lento:
# Exemplo - Ineficiente
Definir variável [ $namel ; Valor: JSONGetElement ( Tabela::JSON1 ; "nome" ) ]
Definir variável [ $name2 ; Valor: JSONGetElement ( Tabela::JSON2 ; "nome" ) ]
Definir variável [ $id1 ; Valor: JSONGetElement ( Tabela::JSON1 ; "id" ) ]
Definir variável [ $id2 ; Valor: JSONGetElement ( Tabela::JSON2 ; "id" ) ]
Ao apenas reordenar os passos de forma para realizar todo o trabalho no mesmo dado JSON antes de trabalhar em outro dado JSON, o cache automático trabalha a seu favor, eliminando a necessidade de analisar dados do mesmo campo duas vezes.
# Exemplo - Melhor
Definir variável [ $namel ; Valor: JSONGetElement ( Tabela::JSON1 ; "nome" ) ]
Definir variável [ $id1 ; Valor: JSONGetElement ( Tabela::JSON1 ; "id" ) ]
Definir variável [ $name2 ; Valor: JSONGetElement ( Tabela::JSON2 ; "nome" ) ]
Definir variável [ $id2 ; Valor: JSONGetElement ( Tabela::JSON2 ; "id" ) ]
O melhor método (e o mais flexível) é usar a função JSONParse para obter o texto JSON de cada fonte, analisá-lo e armazená-lo em uma variável. Dessa forma, ele é analisado apenas uma vez. Então não importa a ordem das operações posteriores (como obter ou definir elementos), já que essas funções JSON podem usar as variáveis, que contêm as representações binárias já analisadas.
# Exemplo - Melhor
Definir variável [ $JSON1 ; Valor: JSONParse ( Tabela::JSON1 ) ]
Definir variável [ $JSON2 ; Valor: JSONParse ( Tabela::JSON2 ) ]
Definir variável [ $namel ; Valor: JSONGetElement ( $JSON1 ; "nome" ) ]
Definir variável [ $name2 ; Valor: JSONGetElement ( $JSON2 ; "nome" ) ]
Definir variável [ $id1 ; Valor: JSONGetElement ( $JSON1 ; "id" ) ]
Definir variável [ $id2 ; Valor: JSONGetElement ( $JSON2 ; "id" ) ]
Como lidar com erros em dados JSON
Se ocorrer um erro durante a análise do parâmetro json
, as funções JSON retornarão "?" seguido por uma mensagem de erro do analisador JSON.
Por exemplo, quando ":" após a chave "padaria" está ausente no Exemplo de dados JSON, esse cálculo
JSONGetElement ( $$JSON ; "padaria.produto[0]id" )
retornará esta mensagem de erro:
? * Line 3, Column 2
Missing ':' after object member name
* Line 13, Column 5
Extra non-whitespace after JSON value.
Para determinar se os dados JSON são válidos antes de usá-los, use a Função JSONFormatElements e teste se o primeiro caractere é "?". Por exemplo:
Definir variável [ $result ; Valor: JSONFormatElements ( $$JSON ) ]
If [ Left ( $result ; 1 ) = "?" ]
# $$JSON contém dados JSON inválidos.
End If
Para determinar se os dados JSON são válidos e um tipo JSON específico antes de usá-lo, você também pode usar a função Função JSONGetElementType. Por exemplo, para testar se $$JSON é um objeto JSON válido:
Definir variável [ $result ; Valor: JSONGetElementType( $$JSON, "" ) ]
If [ $result ≠ JSONObject ]
# $$JSON contém dados JSON inválidos.
End If
Outra maneira de detectar erros é usar a função Função JSONParsedState. Ela pode dizer se os dados JSON foram analisados e são válidos e, em caso afirmativo, que tipo de dados JSON são.
Definir variável [ $result ; Valor: JSONParse ( $$JSON ) ]
Definir variável [ $ParsedState ; Valor: JSONParsedState ( $result ) ]
If [ $ParsedState < 0 ]
# $$JSON foi analisado mas contém dados JSON inválidos.
Else If [ $ParsedState = 0 ]
# $$JSON não foi analisado.
Else If [ $ParsedState > 0 ]
# $$JSON foi analisado e é válido. $ParsedState indica o tipo JSON.
Definir variável [ $type ; Valor:
Case (
$ParsedState = JSONString ; "Tipo JSON é JSONString" ;
$ParsedState = JSONNumber ; "Tipo JSON é JSONNumber" ;
$ParsedState = JSONObject ; "Tipo JSON é JSONObject" ;
$ParsedState = JSONArray ; "Tipo JSON é JSONArray" ;
$ParsedState = JSONBoolean ; "Tipo JSON é JSONBoolean" ;
$ParsedState = JSONNull ; "Tipo JSON é JSONNull"
)
]
Mostrar caixa de diálogo personalizada [ $type ]
End If
Exemplo de dados JSON
O exemplo de dados JSON a seguir contém um objeto "padaria" que possui uma matriz de três objetos "produto", cada um com vários pares de chave-valor.
{
"padaria" :
{
"produto" :
[
{
"id" : "FB1",
"nome" : "Rosquinhas",
"preço" : 1.99,
"estoque" : 43,
"categoria" : "Pães",
"desconto” : true
},
{
"id" : "FB2",
"preço": 22.5,
"nome" : "Bolo de chocolate",
"estoque" : 23,
"categoria" : "Bolos",
"desconto" : true
},
{
"id" : "FB3",
"preço": 3.95,
"nome" : "Baguete",
"estoque" : 34,
"categoria" : "Pães",
"desconto" : true
}
]
}
}
Notas
-
O analisador JSON preserva a ordem dos elementos em uma matriz, mas não a ordem dos elementos em um objeto. Por isso, as funções JSON podem retornar elementos em um objeto em uma ordem diferente da especificada.
-
Nos dados JSON, os valores numéricos fracionários devem usar ponto "." como separador decimal, independentemente do separador especificado pelos formatos de sistema do computador ou dos formatos usados na criação do arquivo do FileMaker Pro.