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



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:

JSON
{
  "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

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.

100%
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?

100%
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

JSON
{
  "name": "Alice",
  "age": 25,
  "is_student": true,
  "scores": [85, 90, 92],
  "address": {
    "city": "Beijing",
    "zip": "100000"
  }
}

(3) Exemplo em XML

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>
💡 Dica: Quase todos os novos projetos usam JSON — ele é conciso, fácil de ler e é analisado rapidamente. Apenas sistemas corporativos legados e dados governamentais ainda usam XML.



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

R
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

R
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
💡 Dica: A magia do jsonlite está na sua capacidade de transformar automaticamente matrizes aninhadas em data frames — em outras linguagens (como o Python), é preciso fazer isso manualmente.



5. Uma explicação detalhada sobre toJSON

(1) Sintaxe básica

R
toJSON(x, pretty = FALSE, auto_unbox = FALSE, dataframe = "columns")

(2) Aplicação prática

R
# 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”
R
# 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

R
# 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

R
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

R
# 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

R
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

R
# 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)

R
# 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

TEXT 📖 Somente leitura
project/
├── config.json          # Profile
├── R/
│   ├── main.R           # Main Program
│   └── utils.R          # Utility Functions
└── data/
    └── input.json       # Input Data

(2) Exemplo de config.json

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

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

R 📖 Somente leitura
# ============================================
# 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
  }
)
77 linhas de lógica (limite de 40, somente leitura)

Resultado esperado (trecho):

TEXT 📖 Somente leitura
=== 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 ou tidyr::unnest() para decompor o JSON.

P: Como faço para converter uma lista retornada por fromJSON em um data.frame? R: Matrizes aninhadas são convertidas automaticamente em data.frames; para listas simples, use as.data.frame() or dplyr::bind_rows() para forçar a conversão.

P: O write_json gera 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, adicione Encoding = "UTF-8" or use saveRDS() (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 null do JSON para o R? R: nullNA, trueTRUE, falseFALSE; matrizes → listas/quadros de dados. O jsonlite lida com isso automaticamente.


📖 Resumo


📝 Exercícios

  1. Problema básico: Construa uma string JSON aninhada (contendo os arranjos name, age e scores), analise-a usando fromJSON() e, em seguida, use toJSON(pretty = TRUE) para gerar uma versão formatada, verificando se os dados aninhados foram corretamente achatados.

  2. 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.

  3. Problema básico: Use xml2 para ler uma string XML simples, extraia os atributos name e o conteúdo de texto de todos os nós <item> e exiba os dados em um data frame.

  4. Problema avançado: Simule uma resposta de API (contendo uma estrutura aninhada de status, data e forecast), analise-a usando fromJSON e, em seguida, use bind_rows para mesclar a matriz forecast em um data frame.

  5. 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.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%