在C中解析JSON
#javascript #网络开发人员 #json #vely

封面图像版权所有Sergio Mijatovic 2022

以不同的方式解析JSON

此示例演示了用Vely在C中解析JSON文本。文本解析包含有关城市的信息。 JSON文件包括一系列国家,其中包括一系列国家,每个国家都有一系列城市。 JSON数据也不是固定的 - 一些数组成员包含的数据不包含其他数组。因此,示例相当涉及。

还显示了UTF8 Unicode数据的使用 - 一些城市的名称中具有此类字符。

JSON文本来自两种不同类型的客户端请求:来自HTML表单,也来自JavaScript/fetch()。第一个使用表格中使用URL Query帖子。第二个演示了使用``application/json content类型''的请求,并使用request-body获取HTTP请求正文。

使用内置哈希语句检索每个JSON数据节点(请参见new-json)。

JSON解析演示了两种方法:

  • 首先,通过搜索特定要素,在这种情况下,所有国家,然后是一个国家下的所有州,然后是国家下的所有城市。这说明了如何处理已知结构但可以更改的通用JSON文档。

  • 第二,通过遍历所有数据节点并将每个数据节点循环中。这对于获取所有数据也很有用,即使您不知道其结构并在此过程中寻找您感兴趣的内容。

应用程序的屏幕截图

这是您可以输入JSON文本进行解析的形式:

这是使用“提取所有数据”按钮提交的结果,其中显示了所有数据节点以及它们的归一化名称(包括层次结构和数组),它们的值和类型:

以下是按下提取特定数据按钮的输出。考虑到数据的层次结构及其名称和值显示:

,找到了特定的数据节点。

您可以从javascript fetch()调用vely代码 - 这是post.html的输出(请参阅“访问应用程序”如何运行它):

设置先决条件

Install Vely您可以使用标准包装工具,例如aptdnfpacmanzypper

因为它在此示例中使用,因此您需要安装Nginx作为Web服务器。

安装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

启动您的应用程序服务器

启动用于Web应用程序的应用程序服务器使用vf FastCGI Process Manager。应用程序服务器将使用UNIX套接字与Web服务器进行通信(即反向Proxy):

vf -w 3 json

这将启动3个守护程序进程,以服务传入的请求。您还可以启动一台自适应服务器,该服务器将增加提供更多请求的过程的数量,并在不需要的过程中逐渐减少这些过程的数量:

vf json

有关更多选项,请参见vf,以帮助您实现最佳性能。

停止您的应用程序服务器:

vf -m quit json

设置Web服务器

这显示了如何连接您在UNIX插座(以vf开头)上侦听的应用程序到Nginx Web服务器。

步骤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(S)从浏览器等Web客户端访问您的应用程序服务器(使用实际IP代替127.0.0.1,如果有所不同):

#Enter JSON and send for parsing :
http://127.0.0.1/json?req=json_form

将文件cities.json(请参阅文件下)的内容复制到表格中的文本区域。

通过Fetch方法从JavaScript运行

您还可以通过JavaScript/Fetch机制测试JSON解析。首先,在单独的目录中将文件复制到您的Web服务器:

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

注意:如果您的服务器在Internet上并且具有防火墙,则可能需要允许HTTP流量 - 请参阅ufwfirewall-cmd等。

文件

您现在已经完成了示例!以下是该项目中的源文件,因此您可以检查其工作原理:

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" : "C\u00F3rdoba",
                        "population": 220000
                    }
                ]
            } ,
            {
                "name": "Sinaloa",
                "city": [
                    {
                        "name" : "Culiac\u00E1n Rosales",
                        "population": 3000000
                    }
                ]
            }
        ]
    }
    ]
}

来自JavaScript(post.html)的呼叫

您可以通过fetch()从JavaScript调用Vely代码。此HTML文件一旦加载(无需按钮)就可以做到这一点,您当然可以更改它以满足您的需求。这还证明了使用post方法与``应用程序/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" : "C\u00F3rdoba", \
                        "population": "220000" \
                    } \
                ] \
            } , \
            {  \
                "name": "Sinaloa", \
                "city": [ \
                    { \
                        "name" : "Culiac\u00E1n 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中的代码解析了所述的城市列表,因此要输入的文本在cities.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_process.vely)来解析JSON

解析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>
}