3

I am new to C++ and cannot figure out how to strip some miscellaneous data from a string and then parse it as JSON.

I've ended up using the most documented JSON parser I could find - jansson. It seems excellent, although I'm stuck at the first hurdle.

My program receives a string in the following format:

5::/chat:{"name":"steve","args":[{"connection":"true"}, { "chatbody" : "I am the body" }]}

I've stripped everything outside the curly brackets with:

std::string str=message;
unsigned pos = str.find("{");
std::string string = str.substr (pos);

That leaves:

{
    "name": "steve",
    "args": [
        {
            "connection": "true"
        },
        {
            "chatbody": "I am the body"
        }
    ]
}

I'm stuck at stage one parsing this. I have converted the string to a char and then tried to use json_loads, but I don't get anything useful out...

The whole thing looks like this:

void processJson(string message)
{
    json_t *root;
    json_error_t error;
    size_t i;

    std::string str=message;
    unsigned pos = str.find("{");
    std::string str3 = str.substr (pos);

    const char * c = str.c_str();

    json_t *data, *sha, *name;

    root = json_loads(c, 0, &error);
    data = json_array_get(root, i);        
    cout << data;

    if(!json_is_object(root))
    {
      fprintf(stderr, "error: commit data %d is not an object\n", i + 1);
    }

}

I need to get the values out, but I just get 01, 02, 03....

is_json_object just says:

error: commit data 1068826 is not an object
error: commit data 1068825 is not an object
error: commit data 1068822 is not an object

What am I doing wrong and how can I properly format this? Ultimately I'll need to iterate over an array but cannot get past this. I'm sure this is just a beginner's mistake.

-EDIT-

Trying to avoid using Boost because of a strict size requirement.

4

4 回答 4

4

您始终可以使用现有的解决方案,例如 Boost 的属性树,它具有自动解析 JSON 文件的功能。就像添加这两个标题一样简单:

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

然后添加这个小代码片段,其中 jsonfile 显然意味着你的文件名。

boost::property_tree::ptree jsontree;
boost::property_tree::read_json(jsonfile, jsontree);

如果您想从 JSON 树中提取信息,您可以这样做,其中 type 是您要提取的数据的类型, insert.key.path.here 是您的密钥的路径,每个父节点键以句点分隔。

jsonfile.get<type>(insert.key.path.here);

另外,我不相信您拥有的 JSON 字符串是有效的。您确实很好地消除了 JSON 字符串本身的多余部分,但我相信这里存在问题:

"connection" : true,

您可以在此处检查 JSON 字符串的有效性:http: //jsonformatter.curiousconcept.com/

于 2013-07-07T18:31:23.153 回答
4

对于 JSON 格式,我通过 C++ 搜索了一个漂亮的打印解决方案,但无济于事。最后,我找到了一些最终转换为 C++ 的 java 代码。尝试以下 JSON 格式:

std::string formattedJson(char *json)
{
    std::string pretty;

    if (json == NULL || strlen(json) == 0)
    {
        return pretty;
    }

    std::string str     = std::string(json);
    bool        quoted  = false;
    bool        escaped = false;
    std::string INDENT  = "    ";
    int         indent  = 0;
    int         length  = (int) str.length();
    int         i;

    for (i = 0 ; i < length ; i++)
    {
        char ch = str[i];

        switch (ch)
        {
            case '{':
            case '[':
                pretty += ch;

                if (!quoted)
                {
                    pretty += "\n";

                    if (!(str[i+1] == '}' || str[i+1] == ']'))
                    {
                        ++indent;

                        for (int j = 0 ; j < indent ; j++)
                        {
                            pretty += INDENT;
                        }
                    }
                }

                break;

            case '}':
            case ']':
                if (!quoted)
                {
                    if ((i > 0) && (!(str[i-1] == '{' || str[i-1] == '[')))
                    {
                        pretty += "\n";

                        --indent;

                        for (int j = 0 ; j < indent ; j++)
                        {
                            pretty += INDENT;
                        }
                    }
                    else if ((i > 0) && ((str[i-1] == '[' && ch == ']') || (str[i-1] == '{' && ch == '}')))
                    {
                        for (int j = 0 ; j < indent ; j++)
                        {
                            pretty += INDENT;
                        }
                    }
                }

                pretty += ch;

                break;

            case '"':
                pretty += ch;
                escaped = false;

                if (i > 0 && str[i-1] == '\\')
                {
                    escaped = !escaped;
                }

                if (!escaped)
                {
                    quoted = !quoted;
                }

                break;

            case ',':
                pretty += ch;

                if (!quoted)
                {
                    pretty += "\n";

                    for (int j = 0 ; j < indent ; j++)
                    {
                        pretty += INDENT;
                    }
                }

                break;

            case ':':
                pretty += ch;

                if (!quoted)
                {
                    pretty += " ";
                }

                break;

            default:
                pretty += ch;

                break;
        }
    }

    return pretty;
}
于 2016-12-29T20:49:52.913 回答
2

我不熟悉您使用的任何 JSON 库,但这里有一些关于可能出现问题的建议。

  • size_t i没有初始化为任何东西,然后被传递到json_array_get.
  • json_array_get传递的是根对象,它不是一个 JSON 数组,而是一个 JSON 对象。在 JSON 术语中,root["args"]将是数组。

当然,根据您的 JSON 库的语义,这可能根本不是问题,但它们对我来说似乎是危险信号。

于 2013-07-07T18:19:50.527 回答
2

Casablanca (REST C++ SDK)有一个非常不错的 JSON 解析器,即使您不使用 HTTP 功能也可以使用它。

您可以将 JSON 解析器文件提取到静态库中,并将其与现有项目链接。要提取的文件是:

src\json\json.cpp
src\json\json_parsing.cpp
src\json\json_serialization.cpp
src\utilities\asyncrt_utils.cpp

include\cpprest\json.h
include\cpprest\xxpublic.h
include\cpprest\basic_types.h
include\cpprest\asyncrt_utils.h

我可以确认这是可行的,因为我最近将它用作我的项目的静态库。

我也尝试使用 Jansson,但 Casablanca 中的解析器只是感觉更易于使用并且具有更好的 Unicode 支持。

于 2014-01-14T09:30:46.670 回答