R: بيانات JSON و XML: دليل شامل لـ jsonlite
آخر تحديث: 2026-08-26
في الدرس السابق، تعرفنا على CSV وExcel — ولكن في عصر الويب، أصبحت البيانات تُستخدم بشكل متزايد بتنسيق JSON (استجابات واجهات برمجة التطبيقات، وملفات التكوين، وقواعد بيانات NoSQL). في هذا الدرس، سنتعرف على الطرق القياسية لقراءة وكتابة JSON في R:
jsonlite، بالإضافة إلى كيفية التعامل مع بيانات XML:xml2.
بعد الانتهاء من هذا الدرس، ستتمكن من تحويل بيانات JSON المتداخلة التي تُرجعها واجهة برمجة التطبيقات (API) إلى إطار بيانات في غضون 5 ثوانٍ، وكذلك كتابة ملفات التكوين الخاصة بك بلغة JSON.
1. ما ستتعلمه
- ما هما JSON و XML، ومتى ينبغي استخدامهما؟
- تثبيت حزمة jsonlite و 4 وظائف أساسية
- fromJSON: يقرأ ملفات JSON (يعمل على تسوية البيانات المتداخلة)
- toJSON تُنتج ملف JSON
- دليل عملي حول JSON المتداخل (استجابات واجهة برمجة التطبيقات)
- xml2: قراءة ملف XML
- التحويل بين JSON و data.frame
- تجربة عملية: استخراج البيانات من واجهة برمجة التطبيقات (API) بشكل دفعي
2. قصة مجموعة بيانات واجهة برمجة التطبيقات (API)
(1) المشكلة: تعرض واجهة برمجة التطبيقات (API) بيانات JSON متداخلة
يعمل بوب على تطوير تطبيق للطقس ويحتاج إلى استرداد البيانات من واجهة برمجة تطبيقات (API) خاصة بالطقس:
{
"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"}
]
}
}
أراد استخراج «توقعات الطقس لـ 7 أيام» وحفظها في لغة R لتحليلها. في لغة Python، استغرق الأمر 10 أسطر من التعليمات البرمجية requests + json؛ أما في لغة R، فقد تم ذلك في سطر واحد—
(2) الحل باستخدام لغة 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 متداخل في 3 أسطر فقط من الكود. هذه هي «السحر» الذي يتميز به 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 مقابل XML: متى يستخدم أي منهما؟
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) مقارنة بين الصيغتين
| الخاصية | JSON | XML |
|---|---|---|
| الاسم الكامل | ترميز كائنات جافا سكريبت | لغة الترميز القابلة للتوسيع |
| بناء الجملة | {"key": "value"} |
<key>value</key> |
| سهولة القراءة | الإيجاز | الإسهاب |
| نوع البيانات | عدد، سلسلة، منطقية، فارغة، مصفوفة، كائن | جميع السلاسل |
| سرعة التحليل | سريعة | أبطأ |
| حالات الاستخدام الرئيسية | واجهات برمجة التطبيقات على الويب، NoSQL، ملفات التكوين | الأنظمة المؤسسية القديمة، SOAP، المستندات (RSS، SVG) |
| حزمة R | jsonlite |
xml2 |
(2) مثال على JSON
{
"name": "Alice",
"age": 25,
"is_student": true,
"scores": [85, 90, 92],
"address": {
"city": "Beijing",
"zip": "100000"
}
}
(3) مثال على 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. الوظائف الأساسية الأربع لـ jsonlite
(1) جدول مرجعي سريع للوظائف
| الوظيفة | الغرض |
|---|---|
fromJSON() |
JSON → كائن R (قائمة / إطار بيانات) |
toJSON() |
كائن R → سلسلة JSON |
read_json() |
قراءة ملفات JSON/عناوين URL |
write_json() |
كتابة ملف JSON |
(2) شرح مفصل لـ 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) التسوية التلقائية لبيانات JSON المتداخلة
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. شرح مفصل لوظيفة toJSON
(1) قواعد النحو الأساسية
toJSON(x, pretty = FALSE, auto_unbox = FALSE, dataframe = "columns")
(2) التطبيق العملي
# 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) المعلمات الرئيسية
| المعلمة | الوظيفة | القيمة الافتراضية |
|---|---|---|
pretty |
التنسيق (مع المسافة البادئة) | FALSE |
auto_unbox |
إزالة المصفوفة تلقائيًا من المتجهات ذات الطول 1 | FALSE |
dataframe |
وضع عرض إطار البيانات | "أعمدة" |
# 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: الكتابة إلى ملف
# 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. تدريب عملي: استخراج بيانات واجهة برمجة التطبيقات (API) دفعة واحدة
(1) استدعاءات واجهة برمجة التطبيقات (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) التقاط بيانات عدة مستخدمين دفعة واحدة
# 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: قراءة ملفات XML
(1) التثبيت والوظائف الأساسية
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) تجربة عملية: قراءة موجزات 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) تدريب عملي: قراءة ملفات SVG (صور 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. تدريب عملي: قراءة وكتابة ملفات التكوين بتنسيق JSON
(1) هيكل المشروع
project/
├── config.json # Profile
├── R/
│ ├── main.R # Main Program
│ └── utils.R # Utility Functions
└── data/
└── input.json # Input Data
(2) مثال على ملف 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) تحميل إعدادات برنامج 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. مثال كامل: استخراج البيانات من واجهة برمجة التطبيقات (API) + تخزين البيانات بتنسيق JSON
فيما يلي مثال على مسار عمل كامل يربط بين جميع المفاهيم التي تم تناولها في هذا الدرس.
▶ مثال: استخراج بيانات واجهة برمجة تطبيقات الطقس وحفظها
# ============================================
# 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
}
)
النتائج المتوقعة (مقتطف):
=== 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
❓ أسئلة شائعة
fromJSON إلى data.frame؟as.data.frame() or dplyr::bind_rows() لإجبار النظام على إجراء التحويل.null في JSON إلى R؟null → NA، true → TRUE، false → FALSE؛ المصفوفات → القوائم/إطارات البيانات. يتولى jsonlite هذه العملية تلقائيًا.📖 ملخص
- يُعد JSON التنسيق القياسي لواجهة برمجة التطبيقات على الويب، في حين لا يزال XML مستخدمًا في الأنظمة المؤسسية القديمة، وRSS، وSVG.
- jsonlite هو المعيار القياسي لمعالجة JSON في R: يعتمد على لغة R وحدها، ويقوم تلقائيًا بتسوية البيانات المتداخلة، ويقدم أداءً جيدًا
- 4 وظائف أساسية:
fromJSON/toJSON/read_json/write_json - سحر jsonlite: يتم تحويل المصفوفات المتداخلة تلقائيًا إلى data.frames (في اللغات البرمجية الأخرى، يتعين عليك تسويتها يدويًّا)
toJSON()المعلمات الرئيسية:pretty(التنسيق)،auto_unbox(تحويل القيم الفردية إلى تنسيق غير مصفوفة)- xml2 قراءة XML: 4 دوال
read_xmlxml_find_allxml_textxml_attr، باستخدام XPath - لغة JSON مناسبة لتخزين ملفات التكوين (سهلة القراءة + متعددة الاستخدامات)؛ بينما تستخدم لغة R
saveRDSداخليًّا (مع الحفاظ على أنواع البيانات)
📝 تمارين
-
المشكلة الأساسية: قم بإنشاء سلسلة JSON متداخلة (تحتوي على المصفوفات
nameوageوscores)، وقم بتحليلها باستخدامfromJSON()، ثم استخدمtoJSON(pretty = TRUE)لإخراج نسخة منسقة، مع التحقق من أن البيانات المتداخلة قد تم تسويتها بشكل صحيح. -
تمرين أساسي: قم بتحويل إطار بيانات (5 صفوف، 3 أعمدة) إلى صيغة JSON، ثم استخدم
read_json()لإعادة قراءته والتحقق من اكتمال البيانات. -
المشكلة الأساسية: استخدم
xml2لقراءة سلسلة XML بسيطة، واستخراج سماتnameوالمحتوى النصي لجميع العقد<item>، وإخراج البيانات في إطار بيانات. -
مشكلة متقدمة: قم بمحاكاة استجابة واجهة برمجة التطبيقات (تحتوي على بنية متداخلة من
statusوdataوforecast)، وقم بتحليلها باستخدامfromJSON، ثم استخدمbind_rowsلدمج المصفوفةforecastفي إطار بيانات. -
التحدي: اكتب برنامجًا كاملاً يقوم بما يلي: ① إنشاء ملف JSON يحتوي على بيانات الطقس لثلاث مدن؛ ② قراءة واستخراج درجة الحرارة الحالية لجميع المدن؛ ③ حساب متوسط درجة الحرارة على المستوى الوطني؛ ④ كتابة النتيجة في ملف جديد باستخدام
write_json. التقط لقطة شاشة لإخراج وحدة التحكم واحفظها.