Разбор JSON в C с помощью фреймворка Vely

Разбор 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 )):

Шаг 2:

Наконец, перезапустите Nginx:

Доступ к серверу приложений из браузера

Используйте следующие URL-адреса для доступа к серверу приложений из веб-клиента, такого как браузер (используйте фактический IP-адрес вместо 127.0.0.1, если он отличается):

Скопируйте содержимое файла city.json (см. в разделе ФАЙЛЫ) в текстовую область формы.

Запуск из Javascript с помощью метода выборки

Вы также можете протестировать синтаксический анализ JSON с помощью механизма Javascript/fetch. Сначала скопируйте файл на свой веб-сервер в отдельный каталог:

Протестируйте его (используйте свой веб-адрес вместо 127.0.0.1, если не тестируете локально):

Примечание: если ваш сервер находится в Интернете и на нем есть брандмауэр, вам может потребоваться разрешить 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>

}



Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE