#ifndef __JsonSupport_h_ #define __JsonSupport_h_ #include #include #include ///////////////////////////////////////////////////////////////////// // This unit gives you a way to create JSON formatted data for // output. // // The interface for this unit was heaviliy inspired by XmlSupport.h // and the PHP code that does the same thing. These were tremendously // successful because they were so easy to use. In particular, I // could create a whole tree with a single statement like // node['header']['errors'][5][-1].name = 'New Error'; // // JSON is different from XML because in JSON each node can have a // different data type. It's something like a variant in Windows / // Delphi. // // We don't have any way to read the JSON data because it of the // variant structure. We would need to check the type of the data // at run time before reading anything. That would be slow and // painful and not good C++ style. Presumably we have a better way // to access the data already. Presumably we are producing this // structure strictly to send the data to someone else. Based on // the way XmlNode is used, I don't see any problems with this. // // As a variant you can set a JsonNode to any type you want. But // if you want to add to an array the operation, there are some // preconditions. If the node is already an array, you can continue // to use it as an array. If is already an object, you can continue // to use it as an object. If it is null when you start, and you // try to use it as an array or object, this will automatically // initialize the node as an empty array or object. If the JsonNode // has any other type, and you try to access it as an array or // object then you will cause an exception. // // As in XmlNode, all contents are COPIED into the node; they are // not stored by reference. This makes things simpler because // you don't have to worry about when to throw things away. This // worked well with XmlNode. Typically a function will take a // parent node as an input (by reference) and will add data to that // node, rather than returning a node. We could also add a swap // method with the standard STL semantics, if needed. // // http://en.wikipedia.org/wiki/Json class JsonNode { public: enum Type { null, integer, real, string, boolean, array, object }; struct InvalidTypeException { Type expected; Type found; }; private: Type _type; int _integerValue; double _realValue; std::string _stringValue; bool _booleanValue; std::vector< JsonNode > _arrayValue; std::map< std::string, JsonNode > _objectValue; void clearAll(); void addToString(std::string &output) const; public: // The default value for a node is null. This is required to allow us // to create complicated arrays in one statement, as described above. JsonNode() : _type(null) { } // Assignment. These all return a refernce to this, to match the standard // = operator. JsonNode &setToNull(); JsonNode &operator =(int i); JsonNode &operator =(double d); JsonNode &operator =(std::string s); JsonNode &operator =(const char *s) { // By default a char * would be converted to a bool, not a std::string! return *this = (std::string)s; } JsonNode &operator =(bool b); JsonNode &setToEmptyArray(); JsonNode &setToEmptyObject(); JsonNode &operator =(JsonNode const &other); // This will find and return the child with the given name. If no such // child exists, a new one will be created with the default value of null. // If this node is initially null, we will automatically convert it to an // empty object. If the type of this node was not null or object before // this call, it will raise an exception. JsonNode &operator[](std::string s); // This will find and return a child in the given position. If i is -1, // a new child with the default value of null will be created and returned. // (The size of the array will be incremented by 1.) If i >= 0 then we look // for the child in position i. 0 is the first position. If i is past the // end of the array, then the array will be extended to have i+1 elements. // (So we will add the minimum number of elements required to make i a valid // index.) If this node is initially null, we will automatically convert // it to an empty array. If the type of this node was not null or array, // it will raise an exception. JsonNode &operator[](int i); std::string asString() const; }; #endif