5.4. Documentos JSON
JSON é a abreviação de Java Script Object Notation. Trata-se de um formato de dados que ficou muito popular nas aplicações Web, principalmente entre as APIs de serviços, pela facilidade de estruturar dados para intercâmbio entre as aplicações. Conforme veremos nas seções seguintes, um documento JSON é de fácil leitura e escrita, possibilitando as aplicações manipularem dados codificados neste formato.
O documento apresentado abaixo, obtido através do serviço Google Elevation API
, ilustra a notação empregada em documentos JSON:
{
"results": [
{
"elevation": 18.1,
"location": {
"lat": 30.0,
"lng": -73.0
},
"resolution": 76.0
}
],
"status": "OK"
}
Esse documento se parece muito com um dicionário na linguagem de programação Python, onde temos um par de chaves ({
e }
) delimitando os pares de chave-valor do dicionário. Os pares de chave-valor, por sua vez, correspondem a:
strings e arrays;
strings e novos objetos (ou dicionarios);
string e valores numéricos;
string e valores textuais.
5.4.1. Sintaxe de Documentos JSON
Um documento JSON contém um valor que pode ser representado por um dos seguintes tipos: object
, array
, number
, string
, true
, false
, ou null
. Cada um desses valores possui uma notação específica.
O tipo number
representa valores numéricos, não diferenciando entre valores inteiros e números em ponto-flutuante:
1234
8.9
O tipo string
é usado para representação de valores textuais, sendo delimitado por aspas duplas ("
), suportando caracteres Unicode e sequências de escape utilizando o caractere \
:
"Uma string deve\n aparecer entre aspas duplas"
Os valores true
e false
, associados ao tipo lógico são escritos da seguinte forma:
true
false
O tipo array
permite representar uma sequência de valores, inclusive de tipos diferentes. Utiliza-se um par de colchetes ([
e ]
) como delimitador dos elementos pertencentes à sequência, sendo os elementos separados por vírgula (,
):
["CAP-419", "SER-347", 2021, true ]
O tipo object
é representado por um conjunto de pares chave-valor
, delimitados por um par de chaves ({
e }
):
{
"nome": "Gilberto",
"sobrenome": "Queiroz",
"idade": 30,
"pesquisador": true,
"pais": [ "Gilberto Queiroz", "Telma Queiroz" ],
"endereco": {
"rua": "Av. dos Astronautas",
"numero": 1758,
"bairro": "Jardim da Granja",
"cidade": "São José dos Campos",
"uf": "SP",
"cep": "12227-010"
}
}
Repare que o tipo object
permite estruturar dados que possuam certa complexidade. No exemplo acima, a chave endereco
corresponde a um valor que também é um objeto, e a chave pais
corresponde a uma sequência de valores do tipo string
.
5.4.2. Validadores de Documentos JSON
Existem na Internet vários aplicativos online que possibilitam validar a estrutura de um documento JSON, isto é, permite sabermos se o documento respeita a sintaxe (ou notação) JSON.
Um bom aplicativo é o JSONLint - The JSON Validator. Acesse o endereço desse aplicativo e verifique os erros no fragmento abaixo:
{
"nome": Gilberto,
"sobrenome": 'Queiroz',
"idade": 30,
"pesquisador": true,
"pais": [ "Gilberto Queiroz", "Telma Queiroz" ]
"endereco": {
"rua": "Av. dos Astronautas",
"numero": 1758,
"bairro": "Jardim da Granja",
"cidade": "São José dos Campos",
"uf": "SP",
"cep": "12227-010"
}
}
Exercício: Tente corrigir o fragmento acima para que ele se torne um documento válido JSON.
5.4.3. Leitura e Escrita de Arquivos JSON
A biblioteca padrão do Python possui um módulo denominado json que pode ser utilizado para manipulação de documentos JSON. A forma mais simples de trabalhar este formato é através da representação de dicionários do Python, que possui uma mapeamento direto com o tipo object
da notação JSON. Para começar nosso exercício com a manipulação de textos no formato JSON, vamos importar a biblioteca JSON e transformar um dicionário em um documento no formato JSON:
1import json
2
3endereco = {
4 'rua': 'Av. dos Astronautas',
5 'numero': 1758,
6 'bairro': 'Jardim da Granja',
7 'cidade': 'São José dos Campos',
8 'UF': 'SP',
9 'CEP': '12227-010'
10}
11
12endereco_json = json.dumps(endereco)
13
14print(endereco_json)
Repare no trecho de programa acima, que o identificador endereco_json
fica associado a uma string
contendo todo o texto do documento JSON equivalente ao dicionário informado na função json.dumps
. Esse processo de transformar um objeto Python em um documento texto é conhecido por serialização.
De maneira similar, podemos ler um texto representando um documento JSON e transformá-lo em um dicionário Python, através da função json.loads
:
1import json
2
3doc = '{"rua": "Av. dos Astronautas", "numero": 1758, \
4 "bairro": "Jardim da Granja", \
5 "cidade": "S\\u00e3o Jos\\u00e9 dos Campos", \
6 "UF": "SP", "CEP": "12227-010"}'
7
8endereco = json.loads(doc)
9
10print( endereco['rua'] )
11print( endereco['numero'] )
12print( endereco['cidade'] )
No trecho de código acima podemos observar que após transformar a string contendo o texto do documento JSON (doc
) em um dicionário Python através da função json.loads
, podemos acessar os valores associados às chaves rua
, numero
e cidade
no dicionário (endereco
). Este processo de transformar um documento texto em um objeto Python é chamado de deserialização.
Agora vamos ler um documento JSON.
{
"indexed": {
"date-parts": [ [2020, 4, 17] ],
"date-time": "2020-04-17T06:23:05Z",
"timestamp": 1587104585191
},
"reference-count": 55,
"publisher": "MDPI AG",
"issue": "8",
"license": [
{
"URL": "https://creativecommons.org/licenses/by/4.0/",
"start": {
"date-parts": [ [2020, 4, 16] ],
"date-time": "2020-04-16T00:00:00Z",
"timestamp": 1586995200000
}
}
],
"abstract": "In recent years, Earth observation (EO) satellites...",
"DOI": "10.3390/rs12081253",
"type": "article-journal",
"created": {
"date-parts": [ [2020, 4, 16] ],
"date-time": "2020-04-16T17:01:39Z",
"timestamp": 1587056499000
},
"page": "1253",
"source": "Crossref",
"is-referenced-by-count": 0,
"title": "An Overview of Platforms for Big Earth Observation Data Management and Analysis",
"prefix": "10.3390",
"volume": "12",
"author": [
{
"ORCID": "http://orcid.org/0000-0003-3239-2160",
"authenticated-orcid": false,
"given": "Vitor C. F.",
"family": "Gomes",
"sequence": "first",
"affiliation": []
},
{
"ORCID": "http://orcid.org/0000-0001-7534-0219",
"authenticated-orcid": false,
"given": "Gilberto R.",
"family": "Queiroz",
"sequence": "additional",
"affiliation": []
},
{
"ORCID": "http://orcid.org/0000-0003-2656-5504",
"authenticated-orcid": false,
"given": "Karine R.",
"family": "Ferreira",
"sequence": "additional",
"affiliation": []
}
],
"member": "1968",
"published-online": { "date-parts": [ [2020, 4, 16] ] },
"container-title": "Remote Sensing",
"original-title": [],
"language": "en",
"link": [{
"URL": "https://www.mdpi.com/2072-4292/12/8/1253/pdf",
"content-type": "unspecified",
"content-version": "vor",
"intended-application": "similarity-checking"
}],
"deposited": {
"date-parts": [ [2020, 4, 16] ],
"date-time": "2020-04-16T17:51:19Z",
"timestamp": 1587059479000
},
"score": 1.0,
"subtitle": [],
"short-title": [],
"issued": {
"date-parts": [ [2020, 4, 16] ]
},
"references-count": 55,
"journal-issue": {
"published-online": {
"date-parts": [ [2020, 4] ]
},
"issue": "8"
},
"alternative-id": ["rs12081253"],
"URL": "http://dx.doi.org/10.3390/rs12081253",
"ISSN": ["2072-4292"],
"subject": ["General Earth and Planetary Sciences"],
"container-title-short": "Remote Sensing"
}
Podemos ler o arquivo artigo.json
utilizando a função interna do Python chamada open()
, como mostrado abaixo:
1import json
2
3with open( 'artigo.json', 'r' ) as arq_json:
4 artigo = json.load( arq_json )
5
6 print( artigo['title'] )
7
8 for autor in artigo['author']:
9 print( 'Nome: {} {}'.format(autor['given'], autor['family']) )
Repare que após a abertura do arquivo na linha 03
, realizamos a leitura dos dados deste arquivo na linha 04
através da função json.load()
. Após a transformação do arquivo em um dicionário Python, podemos acessar os campos desse dicionário usando o operador []
, recuperando assim o título do artigo e sua lista de autores.
Para gravar um arquivo JSON podemos usar a função json.dump
como mostrado no trecho de código abaixo:
1import json
2
3endereco = {
4 'rua': 'Av. dos Astronautas',
5 'numero': 1758,
6 'bairro': 'Jardim da Granja',
7 'cidade': 'São José dos Campos',
8 'UF': 'SP',
9 'CEP': '12227-010'
10}
11
12with open('endereco.json', 'w') as arq_json:
13 json.dump(endereco, arq_json)
Após a execução do trecho de código acima, você deverá ter um arquivo chamado endereco.json
contendo a serialização do dicionário Python endereco
na forma de um arquivo JSON.
Nota
As funções json.dump
e json.dumps
aceitam um argumento nomeado, indent
, que pode ser usado para controlar a indentação do documento JSON. Na linha 14
do trecho de código acima, poderíamos utilizar um nível de indentação com 4
espaços:
json.dump(endereco, arq_json, indent=4)