Разбор JSON в C с помощью фреймворка Vely
21 ноября 2022 г.Изображение на обложке Copyright Sergio Mijatovic 2022
Различные способы анализа JSON
В этом примере демонстрируется синтаксический анализ текста JSON с помощью Vely на языке C. Анализируемый текст содержит информацию о городах. Документ JSON включает в себя массив стран, который включает в себя массив штатов, в каждом из которых есть массив городов. Данные JSON также не фиксированы — некоторые элементы массива содержат данные, которых нет в других. Так что пример довольно сложный.
Также показано использование данных Unicode UTF8 — в названиях некоторых городов есть такие символы.
Текст JSON поступает из клиентских запросов двух разных типов: из HTML-формы, а также из Javascript/fetch(). Первый использует POST URL-запрос из формы. Второй демонстрирует запрос с типом содержимого "application/json" и использование тела запроса для получения тела HTTP-запроса. .
Каждый узел данных JSON извлекается с помощью встроенных операторов хеширования (см. new-json).
Разбор JSON демонстрирует два метода:
* Во-первых, путем поиска определенных элементов, в данном случае всех стран, затем всех штатов в стране, а затем всех городов в штате. Это показывает, как работать с общим документом JSON, структура которого известна, но может измениться. * Во-вторых, путем обхода всех узлов данных и получения каждого из них в цикле. Это полезно, чтобы получить все данные, даже если вы не знаете их структуру, и попутно искать то, что вас интересует.
Скриншоты приложения
Это форма, в которой вы можете ввести текст JSON для анализа:
Это результат отправки с помощью кнопки "Извлечь все данные", где отображаются все узлы данных вместе с их нормализованными именами (включая иерархию и массивы), их значениями и типами:
Ниже приведен результат нажатия кнопки «Извлечь определенные данные». Находятся определенные узлы данных с учетом иерархии данных и отображаются их имена и значения:
Вы можете вызвать код Vely из Javascript fetch() — это вывод из post.html (см. приложение Access... о том, как его запустить):
Настройка предварительных условий
Установите Vely — вы можете использовать стандартные инструменты упаковки, такие как apt, dnf , pacman или zypper.
Поскольку он используется в этом примере, вам потребуется установить Nginx. в качестве веб-сервера.
После установки Vely включите подсветку синтаксиса в vim, если вы его используете:
vv -m
Получить исходный код
Исходный код является частью установки Vely. Рекомендуется создать отдельный каталог исходного кода для каждого приложения (и вы можете назвать его как хотите). В этом случае распаковка исходного кода сделает это за вас:
tar xvf $(vv -o)/examples/json.tar.gz
cd json
Настройка приложения
Первый шаг — создать приложение. Приложение будет называться «json», но вы можете назвать его как угодно (если вы это сделаете, измените его везде). Это просто сделать с помощью vf:
sudo vf -i -u $(whoami) json
Это создаст новый домашний каталог приложения (который находится в /var/lib/vv/json
) и выполнит настройку приложения за вас. В основном это означает создание различных подкаталогов в домашней папке и назначение им привилегий. В этом случае только текущий пользователь (или результат команды whoami
Linux) будет владеть этими каталогами с привилегиями 0700; это означает безопасную установку.
Создать приложение
Используйте утилиту vv для создания приложения:
vv -q
Запустите сервер приложений
Чтобы запустить сервер приложений для вашего веб-приложения, используйте vf диспетчер процессов FastCGI. Сервер приложений будет использовать сокет Unix для связи с веб-сервером (т. е. обратный прокси-сервер):
vf -w 3 json
Это запустит 3 процесса демона для обслуживания входящих запросов. Вы также можете запустить адаптивный сервер, который будет увеличивать количество процессов для обслуживания большего количества запросов и постепенно сокращать количество процессов, когда они не нужны:
vf json
См. vf, чтобы узнать о дополнительных параметрах, которые помогут вам добиться максимальной производительности.
Чтобы остановить сервер приложений:
vf -m quit json
Настройка веб-сервера
Здесь показано, как подключить ваше приложение, прослушивающее сокет Unix (начинается с vf), к веб-серверу Nginx.
Шаг 1:
Вам потребуется отредактировать файл конфигурации Nginx. Для Ubuntu и подобных:
sudo vi /etc/nginx/sites-enabled/default
в то время как в Fedora и других системах это может быть по адресу:
sudo vi /etc/nginx/nginx.conf
Добавьте следующее в раздел «сервер {}» («json» — это имя вашего приложения, но в целом это может быть любой URL-адрес приложения, см. request_URL а>)):
location /json { include /etc/nginx/fastcgi_params; fastcgi_pass unix:///var/lib/vv/json/sock/sock; }
Шаг 2:
Наконец, перезапустите Nginx:
sudo systemctl restart nginx
Доступ к серверу приложений из браузера
Используйте следующие URL-адреса для доступа к серверу приложений из веб-клиента, такого как браузер (используйте фактический IP-адрес вместо 127.0.0.1, если он отличается):
#Enter JSON and send for parsing :
http://127.0.0.1/json?req=json_form
Скопируйте содержимое файла city.json (см. в разделе ФАЙЛЫ) в текстовую область формы.
Запуск из Javascript с помощью метода выборки
Вы также можете протестировать синтаксический анализ JSON с помощью механизма Javascript/fetch. Сначала скопируйте файл на свой веб-сервер в отдельный каталог:
sudo mkdir /var/www/html/velytest
sudo cp post.html /var/www/html/velytest
Протестируйте его (используйте свой веб-адрес вместо 127.0.0.1, если не тестируете локально):
http://127.0.0.1/velytest/post.html
Примечание: если ваш сервер находится в Интернете и на нем есть брандмауэр, вам может потребоваться разрешить HTTP-трафик — см. ufw, firewall-cmd и т. д.< /p>
ФАЙЛЫ
С этим примером покончено! Ниже приведены исходные файлы этого проекта, чтобы вы могли изучить, как он работает:
Документ JSON (cities.json)
Это документ JSON, который вы вводите в форму для синтаксического анализа. Он содержит страны, штаты и города вместе с их населением.
{ "country": [
{
"name": "USA",
"state": [
{
"name": "Arizona",
"city": [
{
"name" : "Phoenix",
"population": 5000000
} ,
{
"name" : "Tuscon",
"population": 1000000
}
]
} ,
{
"name": "California",
"city": [
{
"name" : "Los Angeles",
"population": 19000000
},
{
"name" : "Irvine"
}
]
}
]
} ,
{
"name": "Mexico",
"state": [
{
"name": "Veracruz",
"city": [
{
"name" : "Xalapa-Enríquez",
"population": 8000000
},
{
"name" : "Cu00F3rdoba",
"population": 220000
}
]
} ,
{
"name": "Sinaloa",
"city": [
{
"name" : "Culiacu00E1n Rosales",
"population": 3000000
}
]
}
]
}
]
}
Вызов из Javascript (post.html)
Вы можете вызвать свой код Vely из Javascript с помощью fetch(). Этот HTML-файл сделает это, как только загрузится (нет кнопок для нажатия), вы, конечно, можете изменить его в соответствии с вашими потребностями. Это также демонстрирует использование метода POST с типом содержимого «application/json» для взаимодействия с кодом Vely на стороне сервера.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Vely + JavaScript/Fetch + POST/PUT/PATCH + JSON</title>
</head>
<body>
<h1 class="align">Example: Vely + JavaScript/Fetch + POST/PUT/PATCH + JSON</h1>
<script>
fetch('/json?req=json_process',{
method: 'POST',
headers: {'content-type': 'application/json'},
body: '{ "country": [
{
"name": "USA",
"state": [
{
"name": "Arizona",
"city": [
{
"name" : "Phoenix",
"population": "5000000"
} ,
{
"name" : "Tuscon",
"population": "1000000"
}
]
} ,
{
"name": "California",
"city": [
{
"name" : "Los Angeles",
"population": "4000000"
},
{
"name" : "Irvine"
}
]
}
]
} ,
{
"name": "Mexico",
"state": [
{
"name": "Veracruz",
"city": [
{
"name" : "Xalapa-Enríquez",
"population": "8000000"
},
{
"name" : "Cu00F3rdoba",
"population": "220000"
}
]
} ,
{
"name": "Sinaloa",
"city": [
{
"name" : "Culiacu00E1n Rosales",
"population": "3000000"
}
]
}
]
}
]
}'
})
.then((result) => { return result.text(); })
.then((content) => { document.getElementById("json_output").innerHTML = content; });
</script>
<div id='json_output'></div>
</body>
</html>
Введите JSON (json_form.vely)
Это простая HTML-форма, в которую можно ввести документ JSON. Поскольку код в json_process.vely и json_all.vely анализирует список городов, как описано, текст для ввода указан в файле city.json.
#include "vely.h"
void json_form () {
out-header default
@<h2>Enter JSON</h2>
@<form action="?req=json_process" method="POST">
@ <label for="json_text">JSON text:</label><br>
@ <textarea name="json_text" rows="8" columns="70">
</textarea><br/>
@ <button type="submit">Extract specific data</button>
@ <button type="submit" formaction="?req=json_all">
Extract all data</button>
@ </form>
}
Проанализировать все данные JSON в цикле (json_all.vely)
Это анализирует документ, структуру которого вы можете не знать. Каждый полученный узел данных вы можете проверить в своем коде.
#include "vely.h"
void json_all() {
out-header default
input-param json_text
// Parse json text and display any error and the position of it
new-json define json from json_text status define st
error-text define etext error-position define epos
if (st != VV_OKAY) {
@Could not parse JSON! Error [<<p-out etext>>] at
position <<p-num epos>>.
exit-request
}
// Traverse JSON document, node by node, display as a table of
// all data nodes
read-json json traverse begin
@<table border='1'>
while (1)
{
read-json json traverse key define k value define v
type define t status define s
if (s != VV_OKAY) break;
// Display name, value and type (ignore boolean and type since
// we don't have them)
@<tr>
@<td><<p-out k>></td> <td><<p-out v>></td>
@<td><<p-out t==VV_JSON_TYPE_NUMBER?"Number":
(t==VV_JSON_TYPE_STRING?"String":"Other")>></td>
@</tr>
}
@</table>
}
Разбор JSON путем поиска определенных элементов (json_process.vely)
Проанализируйте документ JSON. Это показывает синтаксический анализ документа, структура которого вам известна, но не имеет фиксированной структуры, поэтому каждый элемент извлекается на основе его нормализованного имени (см. read-json).
#include "vely.h"
void json_process() {
out-header default
// If JSON data sent via URL-encoded GET or POST
input-param json_text
// If JSON data sent in the request body (application/json),
// use that JSON data
request-body json_body
get-req content-type to define ctype
if (!strcmp(ctype, "application/json")) json_text=json_body;
// Parse json text and display any error and the position of it
new-json define json from json_text status define st
error-text define etext error-position define epos
if (st != VV_OKAY) {
@Could not parse JSON! Error [<<p-out etext>>] at
position <<p-num epos>>.
exit-request
}
@Cities found<hr/>
num country_count;
num state_count;
num city_count;
// Start displaying a list
@<ul>
// Look for countries, states and then cities
// Data is organized in hashed arrays, for example
// country[0].state[1].city[0]
// and each can have sub-nodes, such as
// country[0].name
// etc.
for (country_count = 0; ; country_count++) {
// First, build key prefix for a country
(( define json_key_country
@"country"[<<p-num country_count>>]
))
// Search for a country name
(( define json_key_country_name
@<<p-out json_key_country>>."name"
))
// Search for a country name under index [country_count]
read-json json key json_key_country_name
value define country_name status st
if (st != VV_OKAY) break;
// Country found
@<li>Country: <<p-out country_name>><br/>
@<ul>
// Look for states under this country
for (state_count = 0; ; state_count++) {
// Build key prefix for a state
(( define json_key_state
@<<p-out json_key_country>>."state"[<<p-num state_count>>]
))
// Search for state name
(( define json_key_state_name
@<<p-out json_key_state>>."name"
))
// Search for a state name as:
// country[countr_count].state[state_count]
read-json json key json_key_state_name
value define state_name status st
if (st != VV_OKAY) break;
// State found
@<li>State: <<p-out state_name>><br/>
@<ul>
// Look for cities under state
for (city_count = 0; ; city_count++) {
// Build key prefix for city
(( define json_key_city
@<<p-out json_key_state>>."city"[<<p-num city_count>>]
))
// Search for city name
(( define json_key_city_name
@<<p-out json_key_city>>."name"
))
// Search for a city name as:
// country[countr_count].state[state_count].
// city[city_count]
read-json json key json_key_city_name
value define city_name status st
if (st != VV_OKAY) break;
// Found city, get its population
// by building a key for it
(( define json_key_city_population
@<<p-out json_key_city>>."population"
))
// Get city population
read-json json key json_key_city_population
value define city_population status st
if (st != VV_OKAY) city_population="unknown";
// Display city name and its population
@<li>City:<<p-out city_name>>
(<<p-out city_population>>)</li>
}
@</ul>
@</li>
}
@</ul>
@</li>
}
@</ul>
}
Оригинал