C++编写json生成器

十年热恋 提交于 2020-01-28 20:19:06

 

使用C++来编写json生成器的使用来熟悉C++区别于C的使用方法和语法。

 

头文件

/*
json-writer.cpp
*/

#ifndef _JSONWRITER_H_
#define _JSONWRITER_H_

#include<iostream>
#include<string>
#include<stack>
#include<cstdint>
using namespace std;

class JsonWriter
{
    public:
        enum ContainerType
        {
            CONTAINER_TYPE_ARRAY,
            CONTAINER_TYPE_OBJECT
        };

        enum ContainerLayout
        {
            CONTAINER_LAYOUT_INHERIT,
            CONTAINER_LAYOUT_MULTI_LINE,
            CONTAINER_LAYOUT_SINGLE_LINE
        };

        explicit JsonWriter():
            writer(NULL),
            initialIndentDepth(0),
            indent("  "),
            containerPadding(" "),
            keyPaddingLeft(""),
            keyPaddingRight(" "),
            defaultContainerLayout(CONTAINER_LAYOUT_MULTI_LINE),
            forceDefaultContainerLayout(false)
            {

            }
        
        void ConfigureCompressedOutput()
        {
            SetIndent ("");
            SetContainerPadding("");
            SetKeyPaddingLeft("");
            SetKeyPaddingRight("");
            SetDefaultContainerLayout(CONTAINER_LAYOUT_MULTI_LINE);
            SetForceDefaultContainerLayout(true);
        }

        ostream *GetWriter() {return writer; }
        void SetWriter (ostream *writer)
        {
            this->writer = writer;
        }

        int GetInitialIndentDepth()
        {
            return initialIndentDepth;
        }
        void SetInitialIndentDepth(int depth)
        {
            initialIndentDepth = depth;
        }

        const char *GetIndent()
        {
            return indent;
        }
        void SetIndent(const char *indent)
        {
            this->indent = indent;
        }

        const char *GetContainerPadding()
        {
            return containerPadding;
        }
        void SetContainerPadding(const char *padding)
        {
            keyPaddingRight = padding;
        }

        const char *GetKeyPaddingLeft()
        {
            return keyPaddingLeft;
        }
        void SetKeyPaddingLeft(const char *padding)
        {
            keyPaddingLeft = padding;
        }

        const char *GetKeyPaddingRight()
        {
            return keyPaddingRight;
        }
        void SetKeyPaddingRight(const char *padding)
        {
            keyPaddingRight = padding;
        }

        ContainerLayout GetDefaultContainerLayout()
        {
            return defaultContainerLayout;
        }
        void SetDefaultContainerLayout(ContainerLayout layout)
        {
            defaultContainerLayout = layout;
        }

        bool GetForceDeafultContainerLayout()
        {
            return forceDefaultContainerLayout;
        }
        void SetForceDefaultContainerLayout(bool force)
        {
            forceDefaultContainerLayout = force;
        }

        std::ostream& Write()
        {
            if (writer == NULL)
            {
                return std::cout;
            }
            return *writer;
        }

        void WriteEscapedChar (char c);
        void WriteString(const char *str);

        void StartChild (bool isKey);
        void StartChild()
        {
            StartChild (false);
        }

        void StartContainer(ContainerType type, ContainerLayout layout);
        void EndContainer();

        void StartArray()
        {
            StartContainer(CONTAINER_TYPE_ARRAY, CONTAINER_LAYOUT_INHERIT);
        }
        void StartArray(ContainerLayout layout)
        {
            StartContainer(CONTAINER_TYPE_ARRAY, layout);
        }
        void StartShortArray()
        {
            StartContainer(CONTAINER_TYPE_ARRAY, CONTAINER_LAYOUT_SINGLE_LINE);
        }
        void EndArray()
        {
            EndContainer();
        }

        void StartObject()
        {
            StartContainer(CONTAINER_TYPE_OBJECT, CONTAINER_LAYOUT_INHERIT);
        }
        void StartObject(ContainerLayout layout)
        {
            StartContainer(CONTAINER_TYPE_OBJECT, layout);
        }
        void StartShortObject()
        {
            StartContainer (CONTAINER_TYPE_OBJECT, CONTAINER_LAYOUT_SINGLE_LINE);
        }
        void EndObjct()
        {
            EndContainer();
        }

        void Key(const char *key);

        void NullValue();
        void Value(const char *value);
        void Value(std::string value);
        void Value(bool value);

        #define VALUE_DEF(t) void Value (t value) {StartChild(); Write() << value; }
        #define KEYVALUE_DEF(t) void KeyValue (const char *key, t value) { Key (key); Value (value); }

        VALUE_DEF(int8_t)
        VALUE_DEF(uint8_t)
        VALUE_DEF(int16_t)
        VALUE_DEF(uint16_t)
        VALUE_DEF(int32_t)
        VALUE_DEF(uint32_t)
        VALUE_DEF(int64_t)
        VALUE_DEF(uint64_t)
        VALUE_DEF(float)
        VALUE_DEF(double)

        void KeyNullValue( const char *key)
        {
            Key (key);
            NullValue();
        }

        KEYVALUE_DEF(const char *)
        KEYVALUE_DEF(std::string)
        KEYVALUE_DEF(bool)
        KEYVALUE_DEF(int8_t)
        KEYVALUE_DEF(uint8_t)
        KEYVALUE_DEF(int16_t)
        KEYVALUE_DEF(uint16_t)
        KEYVALUE_DEF(int32_t)
        KEYVALUE_DEF(uint32_t)
        KEYVALUE_DEF(int64_t)
        KEYVALUE_DEF(uint64_t)
        KEYVALUE_DEF(float)
        KEYVALUE_DEF(double)

    private:
        ostream *writer;
        int initialIndentDepth;
        const char *indent;
        const char *containerPadding;
        const char *keyPaddingLeft;
        const char *keyPaddingRight;
        ContainerLayout defaultContainerLayout;
        bool forceDefaultContainerLayout;

        struct Container
        {
            ContainerType type;
            ContainerLayout layout;
            bool isKey;
            int childCount;

            Container (ContainerType type , ContainerLayout layout):
                type (type),
                layout(layout),
                isKey(false),
                childCount(0)
                {

                }
        };

        std::stack<Container *> depth;
        void Indent();
};

#endif

 

.cpp文件

/*
json-writer.cpp
*/
#include"json-writer.h"

using namespace std;

void JsonWriter::Indent()
{
    for (int i = 0, s = initialIndentDepth + depth.size(); i < s; i++)
    {
        Write() << indent;
    }
}

void JsonWriter::StartChild(bool isKey)
{
    if (0 == depth.size())
    {
        if (initialIndentDepth > 0)
        {
            Indent();
        }
        return;
    }

    Container *container = depth.top();
    if (container->childCount > 0 &&
        (container->type == CONTAINER_TYPE_ARRAY ||
        (container->type == CONTAINER_TYPE_OBJECT && !container->isKey)))
    {
        Write() << ",";

        if (container->layout == CONTAINER_LAYOUT_SINGLE_LINE)
        {
            Write() << containerPadding;
        }
        else
        {
            Write() << endl;
            Indent();
        }        
    }
    else if (container->childCount == 0)
    {
        Write() << containerPadding;
        if (container->layout == CONTAINER_LAYOUT_MULTI_LINE)
        {
            Write() << endl;
            Indent();
        }
    }
    
    container->isKey = isKey;
    container->childCount++;
}

void JsonWriter::Key (const char *key)
{
    StartChild (true);
    WriteString(key);
    Write() << keyPaddingLeft << ":" << keyPaddingRight;
}

void JsonWriter::NullValue()
{
    StartChild();
    Write() << "null";
}

void JsonWriter::Value(const char * value)
{
    StartChild();
    WriteString(value);
}

void JsonWriter::Value(string value)
{
    StartChild();
    WriteString(value.c_str());
}

void JsonWriter::Value (bool value)
{
    StartChild();
    Write() << (value ? "true" : "false");
}

 
void JsonWriter::StartContainer(ContainerType type, ContainerLayout layout)
{
    if (forceDefaultContainerLayout)
    {
        layout = defaultContainerLayout;
    }
    else if (layout == CONTAINER_LAYOUT_INHERIT)
    {
        if (depth.size() > 0)
        {
            layout = depth.top()->layout;
        }
        else
        {
            layout = defaultContainerLayout;
        }        
    }

    StartChild();
    depth.push(new Container(type, layout));
    Write() << (type == CONTAINER_TYPE_OBJECT ? '{' : '[');
}

void JsonWriter::EndContainer()
{
    Container *container = depth.top();
    depth.pop();

    if (container->childCount > 0)
    {
        if (container->layout == CONTAINER_LAYOUT_MULTI_LINE)
        {
            Write() << endl;
            Indent();
        }
        else
        {
            Write() << containerPadding;
        }        
    }

    Write() << (container->type == CONTAINER_TYPE_OBJECT ? '}' : ']');

    delete container;
}

void JsonWriter::WriteEscapedChar(char c)
{
    switch(c)
    {
        case '"': Write() << "\\\""; break;
        case '\\': Write() << "\\\\"; break;
        case '\b': Write() << "\\b"; break;
        case '\f': Write() << "\\f"; break;
        case '\n': Write() << "\\n"; break;
        case '\r': Write() << "\\r"; break;
        case '\t': Write() << "\\t"; break;
        default: Write() << c; break;
    }
}

void JsonWriter::WriteString(const char *str)
{
    Write() << "\"";
    for (int i = 0; str[i] != 0; i++)
    {
        WriteEscapedChar(str[i]);
    }

    Write() << "\"";
}

 

简单测试代码:

#include<iostream>
#include<cmath>
#include"json-writer.h"

int main()
{
    auto writer = new JsonWriter;
    writer->StartArray();

    writer->StartShortObject();
    writer->KeyValue("name", "shiyanlou");
    writer->KeyValue("age", "3");
    writer->EndObjct();

    writer->StartObject();
    writer->KeyValue("skills", "c++");
    writer->KeyValue("skills", "python");
    writer->KeyValue("skills", "php");
    writer->KeyValue("skills", "java");
    writer->KeyValue("uri", "http://shiyanlou.com");

    writer->Key("path");
    writer->StartArray();
    writer->Value("web");
    writer->Value("algorithm");
    writer->Value("linux");
    writer->EndArray();

    writer->Key("short-array");
    writer->StartShortArray();
    writer->Value(1);
    writer->Value((uint64_t)0xabcdef123456);
    writer->Value(M_PI);
    writer->EndContainer();

    writer->EndObjct();
    writer->Value(false);
    writer->EndArray();

}

 

多种格式测试代码:

#include "json-writer.h"

#define BEGIN_TEST(name)    \
{   \
    JsonWriter *w = new JsonWriter; \
    w->SetInitialIndentDepth(2);    \
    if (compress)   \
    {   \
        w->ConfigureCompressedOutput(); \
    }   \
    cout << #name <<  ":" << endl << endl;   

#define END_TEST    \
    delete w;   \
    cout << endl << endl;    \
}

int main()
{
    bool compress;

    for (int i = 0; i < 2; compress = i == 0, i++)
    {
        BEGIN_TEST(null)
            w->NullValue();
        END_TEST

        BEGIN_TEST(bool-false)
            w->Value(false);
        END_TEST

        BEGIN_TEST(bool-true)
            w->Value(true);
        END_TEST

        BEGIN_TEST(int)
            w->Value(30000);
        END_TEST

        BEGIN_TEST(double)
            w->Value(0.131415926);
        END_TEST

        BEGIN_TEST(empty-string)
            w->Value("");
        END_TEST

        BEGIN_TEST(simple-string)
            w->Value("Hello");
        END_TEST

        BEGIN_TEST(escaped-string)
            w->Value("\"newline\ntab\t\"");
        END_TEST

        BEGIN_TEST(empty-object)
            w->StartObject();
            w->EndObjct();
        END_TEST

        BEGIN_TEST(empty-array)
            w->StartArray();
            w->EndArray();
        END_TEST

        BEGIN_TEST(short-object)
            w->StartShortObject();
            w->KeyValue("name", "Aaron");
            w->EndObjct();
        END_TEST

        BEGIN_TEST(short-array)
            w->StartShortArray();
            for(int i = 0; i < 10; i++)
            {
                w->Value(i);
            }
            w->EndArray();
        END_TEST

        BEGIN_TEST(array-with-object)
            w->StartArray();
                w->StartShortObject();
                    w->KeyValue("name", "Aaron");
                    w->KeyValue("age", 7);
                w->EndObjct();
                w->StartObject();
                    w->KeyValue("animal", "cat");
                    w->KeyValue("life-expectancy", "forever");
                    w->KeyValue("url", "http://catoverflow.com");
                    w->Key("catch-phrases");
                    w->StartArray();
                        w->Value("meow");
                        w->Value("hiss");
                        w->Value("purr");
                    w->EndArray();
                w->EndObjct();  
                w->Value(false);
            w->EndArray();
        END_TEST

        BEGIN_TEST(nested-objects)
            w->StartObject();
                w->Key("a");
                w->StartObject();
                    w->Key("b");
                    w->StartObject();
                        w->Key("c");
                        w->StartObject();
                        w->EndObjct();
                    w->EndObjct();
                w->EndObjct();
            w->EndArray();
        END_TEST

        BEGIN_TEST(nested-arrays)
            w->StartArray();
                w->StartArray();
                    w->StartArray();
                        w->StartArray();
                        w->EndArray();
                    w->EndArray();
                w->EndArray();
            w->EndArray();
        END_TEST
    }

    return 0;
}

 

makefile文件:

CXXFLAGS = -Wall -g -std=c++11

all: test json-writer-test
clean: 
    rm -rf *.o test json-writer-test

test: json-writer.h json-writer.cpp test.cpp
    $(CXX) $(CXXFLAGS) json-writer.h json-writer.cpp test.cpp -o test

json-writer-test: json-writer-test.cpp json-writer.h json-writer.cpp
    $(CXX) $(CXXFLAGS) json-writer.h json-writer.cpp json-writer-test.cpp -o json-writer-test    

 

运行结果就不放了。

 

版权归于实验楼

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!