 
                        
                    Разбор 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>
}
Оригинал
