R: Dados JSON e XML: Um guia completo sobre o jsonlite
Última atualização: 2026-08-26
Na aula anterior, aprendemos sobre CSV e Excel — mas, na era da Web, os dados estão cada vez mais no formato JSON (respostas de API, arquivos de configuração, bancos de dados NoSQL). Nesta aula, aprenderemos os métodos padrão para ler e gravar JSON no R:
jsonlite, bem como lidar com dados XML:xml2.
Ao concluir esta lição, você será capaz de transformar um JSON aninhado, retornado por uma API, em um data frame em 5 segundos e escrever seus próprios arquivos de configuração em JSON.
1. O que você vai aprender
- O que são JSON e XML, e quando devem ser usados?
- Instalação do pacote jsonlite e de quatro funções principais
- fromJSON: Lê JSON (simplifica dados aninhados)
- toJSON gera um JSON
- Guia prático sobre JSON aninhado (respostas de API)
- xml2: Ler um arquivo XML
- Conversão entre JSON e data.frame
- Prática: Extração de dados por meio da API em lote
2. A história de um conjunto de dados de API
(1) Problema: a API retorna JSON aninhado
Bob está desenvolvendo um aplicativo de previsão do tempo e precisa recuperar dados de uma API meteorológica:
{
"status": "ok",
"data": {
"city": "Beijing",
"date": "2024-01-15",
"forecast": [
{"day": "Monday", "high": 5, "low": -3, "weather": "Sunny"},
{"day": "Tuesday", "high": 7, "low": -1, "weather": "Cloudy"},
{"day": "Wednesday", "high": 3, "low": -5, "weather": "Snowy"}
]
}
}
Ele queria extrair a “previsão do tempo para 7 dias” e salvá-la no R para análise. Em Python, foram necessárias 10 linhas de código requests + json; no R, isso foi feito em uma única linha—
(2) Solução usando R
library(jsonlite)
# 1. Reading nested data with a single line of code JSON
weather <- fromJSON("https://api.weather.com/forecast?city=Beijing")
# 2. Extract 7 Weather Forecast(Nested → Data Frame)
forecast <- weather$data$forecast # It's a data frame!
# 3. Write JSON Layout
config <- list(api_key = "xxx", cities = c("Beijing", "Shanghai"))
write_json(config, "config.json", pretty = TRUE)
JSON aninhado em apenas 3 linhas de código. Essa é a “mágica” do jsonlite.
graph LR
A[API URL<br/>weather.com/forecast] --> B[jsonlite::fromJSON]
B --> C{Nested JSON}
C --> D[forecast Array<br/>Auto-rotate data.frame]
C --> E[current Object<br/>Auto-rotate list]
D --> F[dplyr Analysis<br/>7 Weather Forecast]
D --> G[ggplot2 Drawing<br/>Trend Visualization]
E --> H[Real-time Weather Data]
style A fill:#cce5ff
style B fill:#d4edda
style C fill:#fff3cd
style D fill:#f8d7da
style E fill:#e1d4ff
style F fill:#ffe1d4
style G fill:#cce5ff
style H fill:#d4edda
3. JSON x XML: quando usar cada um?
graph TB
subgraph JSON[JSON Faction]
J1[Grammar: Key-value pairs Concise]
J2[Type: Numbers/String/Boolean/Array/Object]
J3[Analysis: Fast C Language Implementation]
J4[R Package: jsonlite]
end
subgraph XML[XML Faction]
X1[Grammar: Nested Tags Long-winded]
X2[Type: All strings]
X3[Analysis: slower]
X4[R Package: xml2]
end
JSON --> J5[Web API / NoSQL / Profile]
XML --> X5[Legacy Enterprise Systems / SOAP / RSS / SVG]
style JSON fill:#d4edda
style XML fill:#f8d7da
(1) Comparação entre os dois formatos
| Propriedade | JSON | XML |
|---|---|---|
| Nome completo | Notação de Objetos JavaScript | Linguagem de Marcação Extensível |
| Sintaxe | {"key": "value"} |
<key>value</key> |
| Legibilidade | Conciso | Prolixo |
| Tipo de dados | Número, String, Booleano, nulo, Matriz, Objeto | Todas as strings |
| Velocidade de análise | Rápida | Mais lenta |
| Principais casos de uso | APIs da Web, NoSQL, arquivos de configuração | Sistemas corporativos legados, SOAP, documentos (RSS, SVG) |
| Pacote R | jsonlite |
xml2 |
(2) Exemplo em JSON
{
"name": "Alice",
"age": 25,
"is_student": true,
"scores": [85, 90, 92],
"address": {
"city": "Beijing",
"zip": "100000"
}
}
(3) Exemplo em XML
<student>
<name>Alice</name>
<age>25</age>
<scores>
<item>85</item>
<item>90</item>
<item>92</item>
</scores>
<address>
<city>Beijing</city>
<zip>100000</zip>
</address>
</student>
4. Quatro funções principais do jsonlite
(1) Tabela de referência rápida de funções
| Função | Finalidade |
|---|---|
fromJSON() |
JSON → objeto R (lista / data.frame) |
toJSON() |
Objeto R → string JSON |
read_json() |
Ler arquivos JSON/URLs |
write_json() |
Gravar um arquivo JSON |
(2) Uma explicação detalhada sobre fromJSON
library(jsonlite)
# 1. Read JSON String
json_str <- '{"name": "Alice", "age": 25}'
fromJSON(json_str)
# $name
# [1] "Alice"
#
# $age
# [1] 25
# 2. Read JSON Documents
df <- fromJSON("data.json")
# 3. Read URL(API)
weather <- fromJSON("https://api.example.com/weather?city=beijing")
# 4. Expand directly into a data frame
json_array <- '[{"name": "A", "age": 20}, {"name": "B", "age": 25}]'
fromJSON(json_array)
# name age
# 1 A 20
# 2 B 25 ← Automatically Rotate Data Frames!
(3) Simplificação automática de JSON aninhado
nested <- '{
"status": "ok",
"data": {
"city": "Beijing",
"forecast": [
{"day": "Monday", "high": 5, "low": -3},
{"day": "Tuesday", "high": 7, "low": -1}
]
}
}'
result <- fromJSON(nested)
str(result)
# List of 2
# $ status: chr "ok"
# $ data : List of 2
# ..$ city : chr "Beijing"
# ..$ forecast :'data.frame': 2 obs. of 3 variables:
# .. ..$ day : chr [1:2] "Monday" "Tuesday"
# .. ..$ high: num [1:2] 5 7
# .. ..$ low : num [1:2] -3 -1
# Automatically Convert Nested Arrays to DataFrames!
result$data$forecast
# day high low
# 1 Monday 5 -3
# 2 Tuesday 7 -1
5. Uma explicação detalhada sobre toJSON
(1) Sintaxe básica
toJSON(x, pretty = FALSE, auto_unbox = FALSE, dataframe = "columns")
(2) Aplicação prática
# 1. Data Frame → JSON
df <- data.frame(name = c("A", "B"), age = c(20, 25))
toJSON(df)
# [{"name":"A","age":20},{"name":"B","age":25}]
# 2. Format the output(Indented)
toJSON(df, pretty = TRUE)
# [
# {
# "name": "A",
# "age": 20
# },
# {
# "name": "B",
# "age": 25
# }
# ]
# 3. List → JSON
config <- list(
api_key = "secret123",
cities = c("Beijing", "Shanghai", "Guangzhou"),
options = list(timeout = 30, retry = 3)
)
toJSON(config, pretty = TRUE)
# {
# "api_key": "secret123",
# "cities": ["Beijing", "Shanghai", "Guangzhou"],
# "options": {
# "timeout": 30,
# "retry": 3
# }
# }
(3) Parâmetros principais
| Parâmetro | Função | Padrão |
|---|---|---|
pretty |
Formatação (com recuo) | FALSE |
auto_unbox |
Remover automaticamente o array de vetores de comprimento 1 | FALSE |
dataframe |
Modo de exibição do data frame | “colunas” |
# auto_unbox:Prevent a single value from becoming an array
toJSON(list(name = "Alice", scores = c(85))) # Default
# {"name":["Alice"],"scores":[85]}
toJSON(list(name = "Alice", scores = c(85)), auto_unbox = TRUE)
# {"name":"Alice","scores":85} ← Do not convert single values to arrays
(4) write_json: Gravar em um arquivo
# Write JSON Document
write_json(config, "config.json", pretty = TRUE)
# Write concisely JSON(No indentation)
write_json(data, "data.json")
# Append to the file(Read first, Merge, then Write)
old <- read_json("data.json", simplifyVector = FALSE)
new <- c(old, list(updated_at = Sys.time()))
write_json(new, "data.json", pretty = TRUE)
6. Prática: Extração em lote de dados da API
(1) Chamadas reais à API
library(jsonlite)
library(dplyr)
# Call a public API(GitHub User Information)
user_info <- fromJSON("https://api.github.com/users/hadley")
str(user_info)
# List of 50+
# $ login : chr "hadley"
# $ id : int 4192
# $ name : chr "Hadley Wickham"
# $ company : chr "@posit-pbc"
# $ location : chr "Houston, TX"
# $ public_repos : int 50
# ...
# Extract Key Fields
info <- tibble(
name = user_info$name,
company = user_info$company,
repos = user_info$public_repos,
followers = user_info$followers
)
print(info)
(2) Captura em lote de vários usuários
# Retrieve multiple items in bulk GitHub Number of repositories per user
users <- c("hadley", "yihui", "jtleek", "rstudio")
repos_data <- lapply(users, function(user) {
info <- fromJSON(paste0("https://api.github.com/users/", user))
tibble(
user = user,
repos = info$public_repos,
followers = info$followers,
created_at = as.Date(info$created_at)
)
}) |> bind_rows()
print(repos_data)
7. xml2: Leitura de arquivos XML
(1) Instalação e funções principais
install.packages("xml2")
library(xml2)
# 4 Core Functions
read_xml() # Read XML Document
xml_find_all() # XPath Query Node
xml_text() # Extract Node Text
xml_attr() # Retrieve Node Properties
(2) Prática: Como ler feeds RSS
# 1. Read RSS(XML Format)
rss <- read_xml("https://www.r-bloggers.com/feed")
# 2. Extract All <item> Node
items <- xml_find_all(rss, "//item")
cat("Found", length(items), "Articles\n")
# 3. Extract the title of each article,Link,Date
articles <- tibble(
title = xml_text(xml_find_all(items, "./title")),
link = xml_attr(xml_find_all(items, "./link"), "href"),
pub_date = xml_text(xml_find_all(items, "./pubDate"))
)
print(head(articles, 3))
(3) Prática: Como ler SVG (imagens em XML)
# SVG is an XML format
svg <- read_xml("logo.svg")
# Extract All <circle> cx, cy, r attributes
circles <- xml_find_all(svg, "//circle")
data.frame(
cx = as.numeric(xml_attr(circles, "cx")),
cy = as.numeric(xml_attr(circles, "cy")),
r = as.numeric(xml_attr(circles, "r"))
)
8. Prática: Lendo e escrevendo arquivos de configuração JSON
(1) Estrutura do projeto
project/
├── config.json # Profile
├── R/
│ ├── main.R # Main Program
│ └── utils.R # Utility Functions
└── data/
└── input.json # Input Data
(2) Exemplo de config.json
{
"api": {
"key": "your-api-key",
"endpoint": "https://api.example.com",
"timeout": 30
},
"cities": ["Beijing", "Shanghai", "Guangzhou", "Shenzhen"],
"options": {
"log_level": "info",
"max_retries": 3
}
}
(3) Carregando a configuração do programa R
# Load Configuration
config <- read_json("config.json", simplifyVector = FALSE)
print(config$cities)
# [1] "Beijing" "Shanghai" "Guangzhou" "Shenzhen"
# Using the Configuration
for (city in config$cities) {
url <- paste0(config$api$endpoint, "?city=", city, "&key=", config$api$key)
data <- fromJSON(url)
# Processing data...
}
# Update Configuration
config$options$log_level <- "debug"
write_json(config, "config.json", pretty = TRUE, auto_unbox = TRUE)
9. Exemplo completo: Extração de dados da API + Persistência em JSON
A seguir, apresentamos um exemplo de um fluxo de trabalho completo que reúne todos os conceitos abordados nesta aula.
▶ Exemplo: Extração e armazenamento de dados da API meteorológica
# ============================================
# Weather API Data Extraction + Persistence
# Features:Simulated Crawling 4 City Weather,Save as JSON
# ============================================
library(jsonlite)
library(dplyr)
# 1. Simulation API Response(For use in actual projects fromJSON(url))
mock_api_response <- function(city) {
set.seed(match(city, c("Beijing", "Shanghai", "Guangzhou", "Shenzhen")))
list(
status = "ok",
data = list(
city = city,
date = Sys.Date(),
current = list(
temp = sample(0:30, 1),
humidity = sample(40:90, 1),
weather = sample(c("Sunny", "Cloudy", "Rainy", "Snowy"), 1)
),
forecast = data.frame(
day = c("Today", "Tomorrow", "The day after tomorrow", "The day after tomorrow"),
high = sample(5:30, 4),
low = sample(-5:15, 4),
weather = sample(c("Sunny", "Cloudy", "Rainy", "Snowy"), 4, replace = TRUE),
stringsAsFactors = FALSE
)
)
)
}
# 2. Batch Scraping 4 City
cities <- c("Beijing", "Shanghai", "Guangzhou", "Shenzhen")
cat("=== Fetching 4 City Weather ===\n")
all_weather <- lapply(cities, mock_api_response)
names(all_weather) <- cities
# 3. Retrieve All Forecasts(Nested → Data Frame)
all_forecast <- bind_rows(lapply(all_weather, function(w) {
fc <- w$data$forecast
fc$city <- w$data$city
fc
}))
cat("\n=== 4 The Future of Cities 4 Weather Forecast ===\n")
print(all_forecast)
# 4. Get the current weather(Nested → Data Frame)
current_weather <- bind_rows(lapply(all_weather, function(w) {
cw <- w$data$current
tibble(
city = w$data$city,
temp = cw$temp,
humidity = cw$humidity,
weather = cw$weather
)
}))
cat("\n=== Current Weather ===\n")
print(current_weather)
# 5. Save as JSON
write_json(all_weather, "all_weather.json", pretty = TRUE, auto_unbox = TRUE)
cat("\n=== Saved all_weather.json ===\n")
# 6. Save as a compressed file JSON(Remove Indentation)
write_json(all_weather, "all_weather_compact.json", auto_unbox = TRUE)
# 7. Read back JSON for verification
reloaded <- read_json("all_weather.json", simplifyVector = FALSE)
cat("\n=== Read-Back Verification ===\n")
cat("Number of cities:", length(reloaded), "\n")
cat("Current Temperature in Beijing:", reloaded$Beijing$data$current$temp, "°C\n")
# 8. Write a concise version for a single city JSON Layout
config <- list(
api_key = "secret-key-xxx",
default_city = "Beijing",
update_interval = 3600,
enabled_cities = cities
)
write_json(config, "config.json", pretty = TRUE, auto_unbox = TRUE)
cat("\n=== The configuration file has been generated config.json ===\n")
# 9. Read the configuration file
loaded_config <- read_json("config.json", simplifyVector = FALSE)
cat("Default City:", loaded_config$default_city, "\n")
cat("Enable City:", paste(loaded_config$enabled_cities, collapse = ", "), "\n")
# 10. Use jsonlite Processing API Error
cat("\n=== Error Handling Examples ===\n")
error_response <- '{"status": "error", "message": "Invalid API key"}'
result <- tryCatch(
{
parsed <- fromJSON(error_response)
if (parsed$status == "error") stop(parsed$message)
parsed
},
error = function(e) {
cat("API Error:", e$message, "\n")
NULL
}
)
Resultado esperado (trecho):
=== 4 The Future of Cities 4 Weather Forecast ===
day high low weather city
1 Today 12 -3 Sunny Beijing
2 Tomorrow 15 0 Cloudy Beijing
3 The day after tomorrow 8 -5 Snowy Beijing
...
=== Current Weather ===
# A tibble: 4 × 4
city temp humidity weather
<chr> <int> <int> <chr>
1 Beijing 18 65 Sunny
2 Shanghai 22 78 Cloudy
3 Guangzhou 28 85 Rainy
4 Shenzhen 26 72 Cloudy
❓ Perguntas Frequentes
P: Como faço para escolher entre JSON e CSV? R: O CSV é adequado para tabelas estruturadas (um registro por linha), enquanto o JSON é adequado para dados aninhados (incluindo matrizes, objetos e hierarquias) ou APIs da Web.
P: Como faço para simplificar um JSON com aninhamento profundo? R: O jsonlite converte automaticamente as matrizes em data frames. Para aninhamento em vários níveis, use
purrr::flatten()para simplificá-lo passo a passo outidyr::unnest()para decompor o JSON.
P: Como faço para converter uma lista retornada por
fromJSONem um data.frame? R: Matrizes aninhadas são convertidas automaticamente em data.frames; para listas simples, useas.data.frame()ordplyr::bind_rows()para forçar a conversão.
P: O
write_jsongera caracteres chineses distorcidos? R: A codificação padrão é UTF-8. Na versão R 4.x, os caracteres chineses normalmente não aparecem distorcidos. Caso apareçam distorcidos, adicioneEncoding = "UTF-8"or usesaveRDS()(formato nativo do R).
P: O que devo escolher, o pacote xml2 ou o XML? R: Use o xml2 para código novo (backend em C++, API simples). O pacote XML ainda pode ser usado para código legado, mas não recebe mais manutenção.
P: Como faço para converter
nulldo JSON para o R? R:null→NA,true→TRUE,false→FALSE; matrizes → listas/quadros de dados. O jsonlite lida com isso automaticamente.
📖 Resumo
- O JSON é o formato padrão das APIs da Web, enquanto o XML ainda é utilizado em sistemas corporativos legados, RSS e SVG.
- O jsonlite é o padrão para o manuseio de JSON no R: depende exclusivamente do R, simplifica automaticamente dados aninhados e oferece bom desempenho
- 4 funções principais:
fromJSON/toJSON/read_json/write_json - A magia do jsonlite: as matrizes aninhadas são convertidas automaticamente em data.frames (em outras linguagens, é preciso achatá-las manualmente)
toJSON()Parâmetros principais:pretty(formatação),auto_unbox(converter valores únicos para o formato que não seja de matriz)- xml2 Ler XML: 4 funções
read_xmlxml_find_allxml_textxml_attr, com XPath - O JSON é adequado para armazenar arquivos de configuração (legível por humanos + versátil); o R usa
saveRDSinternamente (com preservação de tipos)
📝 Exercícios
-
Problema básico: Construa uma string JSON aninhada (contendo os arranjos
name,ageescores), analise-a usandofromJSON()e, em seguida, usetoJSON(pretty = TRUE)para gerar uma versão formatada, verificando se os dados aninhados foram corretamente achatados. -
Exercício básico: Converta um data frame (5 linhas, 3 colunas) para JSON; em seguida, use
read_json()para importá-lo de volta e verifique se os dados estão completos. -
Problema básico: Use
xml2para ler uma string XML simples, extraia os atributosnamee o conteúdo de texto de todos os nós<item>e exiba os dados em um data frame. -
Problema avançado: Simule uma resposta de API (contendo uma estrutura aninhada de
status,dataeforecast), analise-a usandofromJSONe, em seguida, usebind_rowspara mesclar a matrizforecastem um data frame. -
Desafio: Escreva um programa completo que: ① crie um arquivo JSON contendo dados meteorológicos de três cidades; ② leia e extraia a temperatura atual de todas as cidades; ③ calcule a temperatura média nacional; ④ grave o resultado em um novo arquivo usando
write_json. Faça uma captura de tela da saída do console e salve-a.