598 lines
18 KiB
C++
598 lines
18 KiB
C++
#include <assert.h>
|
|
|
|
#include <a8/a8.h>
|
|
#include <a8/xobject.h>
|
|
|
|
#include <json/reader.h>
|
|
#include <tinyxml2.h>
|
|
|
|
namespace a8
|
|
{
|
|
|
|
XObject::XObject()
|
|
{
|
|
}
|
|
|
|
XObject::XObject(a8::XValue& val)
|
|
{
|
|
type_ = XOT_SIMPLE;
|
|
value_.x_value = new a8::XValue(val);
|
|
}
|
|
|
|
XObject::XObject(const a8::XObject& v)
|
|
{
|
|
switch (v.type_) {
|
|
case XOT_SIMPLE:
|
|
{
|
|
value_.x_value = new a8::XValue();
|
|
}
|
|
break;
|
|
case XOT_ARRAY:
|
|
{
|
|
value_.array_value = new std::vector<std::shared_ptr<a8::XObject>>();
|
|
}
|
|
break;
|
|
case XOT_OBJECT:
|
|
{
|
|
value_.object_value = new std::map<std::string, std::shared_ptr<a8::XObject>>();
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
abort();
|
|
}
|
|
break;
|
|
}
|
|
type_ = v.type_;
|
|
*this = v;
|
|
}
|
|
|
|
XObject::~XObject()
|
|
{
|
|
switch (type_) {
|
|
case XOT_SIMPLE:
|
|
{
|
|
if (value_.x_value) {
|
|
delete value_.x_value;
|
|
value_.x_value = nullptr;
|
|
}
|
|
}
|
|
break;
|
|
case XOT_ARRAY:
|
|
{
|
|
if (value_.array_value) {
|
|
delete value_.array_value;
|
|
value_.array_value = nullptr;
|
|
}
|
|
}
|
|
break;
|
|
case XOT_OBJECT:
|
|
{
|
|
if (value_.object_value) {
|
|
delete value_.object_value;
|
|
value_.object_value = nullptr;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
unsigned char XObject::GetType()
|
|
{
|
|
return type_;
|
|
}
|
|
|
|
int XObject::Size()
|
|
{
|
|
assert(type_ == XOT_ARRAY);
|
|
if (type_ == XOT_ARRAY) {
|
|
return value_.array_value->size();
|
|
} else {
|
|
abort();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void XObject::Reset()
|
|
{
|
|
switch (type_) {
|
|
case a8::XOT_SIMPLE:
|
|
{
|
|
}
|
|
break;
|
|
case a8::XOT_ARRAY:
|
|
{
|
|
delete value_.array_value;
|
|
type_ = XOT_SIMPLE;
|
|
value_.x_value = new a8::XValue();
|
|
}
|
|
break;
|
|
case a8::XOT_OBJECT:
|
|
{
|
|
delete value_.object_value;
|
|
type_ = XOT_SIMPLE;
|
|
value_.x_value = new a8::XValue();
|
|
}
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
}
|
|
|
|
void XObject::DeepCopy(a8::XObject& to)
|
|
{
|
|
to.Reset();
|
|
switch (type_) {
|
|
case a8::XOT_SIMPLE:
|
|
{
|
|
if (value_.x_value) {
|
|
if (!to.value_.x_value) {
|
|
to.value_.x_value = new a8::XValue();
|
|
}
|
|
value_.x_value->DeepCopy(*to.value_.x_value);
|
|
} else {
|
|
if (to.value_.x_value) {
|
|
delete to.value_.x_value;
|
|
to.value_.x_value = nullptr;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case a8::XOT_ARRAY:
|
|
{
|
|
to.type_ = XOT_ARRAY;
|
|
to.value_.array_value = new std::vector<std::shared_ptr<a8::XObject>>();
|
|
for (auto& value : *value_.array_value) {
|
|
std::shared_ptr<a8::XObject> xobj_ptr = std::make_shared<a8::XObject>();
|
|
value->DeepCopy(*xobj_ptr.get());
|
|
to.value_.array_value->push_back(xobj_ptr);
|
|
}
|
|
}
|
|
break;
|
|
case a8::XOT_OBJECT:
|
|
{
|
|
to.type_ = XOT_OBJECT;
|
|
to.value_.object_value = new std::map<std::string, std::shared_ptr<a8::XObject>>();
|
|
for (auto& pair : *value_.object_value) {
|
|
std::shared_ptr<a8::XObject> xobj_ptr = std::make_shared<a8::XObject>();
|
|
pair.second->DeepCopy(*xobj_ptr.get());
|
|
(*(to.value_.object_value))[pair.first] = xobj_ptr;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
}
|
|
|
|
a8::XValue XObject::AsXValue()
|
|
{
|
|
assert(type_ == XOT_SIMPLE);
|
|
if (type_ != XOT_SIMPLE) {
|
|
abort();
|
|
return a8::XValue();
|
|
}
|
|
return type_ == XOT_SIMPLE && value_.x_value ? *value_.x_value : a8::XValue();
|
|
}
|
|
|
|
std::shared_ptr<a8::XObject> XObject::operator[] (int idx)
|
|
{
|
|
return At(idx);
|
|
}
|
|
|
|
std::shared_ptr<a8::XObject> XObject::operator[] (const std::string& key)
|
|
{
|
|
return At(key);
|
|
}
|
|
|
|
std::shared_ptr<a8::XObject> XObject::At(int i)
|
|
{
|
|
assert(type_ == XOT_ARRAY);
|
|
if (type_ == XOT_ARRAY) {
|
|
return value_.array_value->at(i);
|
|
} else {
|
|
abort();
|
|
return std::shared_ptr<a8::XObject>();
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<a8::XObject> XObject::At(const std::string& key)
|
|
{
|
|
assert(type_ == XOT_OBJECT);
|
|
if (type_ == XOT_OBJECT) {
|
|
auto itr = value_.object_value->find(key);
|
|
return itr != value_.object_value->end() ? itr->second : std::shared_ptr<a8::XObject>();
|
|
} else {
|
|
abort();
|
|
return std::shared_ptr<a8::XObject>();
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<a8::XObject> XObject::At(const char* key)
|
|
{
|
|
return At(std::string(key));
|
|
}
|
|
|
|
a8::XValue XObject::Get(const std::string& key, a8::XValue defval)
|
|
{
|
|
if (type_ == XOT_OBJECT) {
|
|
auto itr = value_.object_value->find(key);
|
|
return itr != value_.object_value->end() ? itr->second->AsXValue() : defval;
|
|
} else {
|
|
return defval;
|
|
}
|
|
}
|
|
|
|
bool XObject::HasKey(const std::string& key)
|
|
{
|
|
assert(type_ == XOT_OBJECT);
|
|
if (type_ == XOT_OBJECT) {
|
|
auto itr = value_.object_value->find(key);
|
|
return itr != value_.object_value->end();
|
|
} else {
|
|
abort();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool XObject::HasKey(int i)
|
|
{
|
|
assert(type_ == XOT_ARRAY);
|
|
if (type_ == XOT_ARRAY) {
|
|
return i >= 0 && i < (int)value_.array_value->size();
|
|
} else {
|
|
abort();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const a8::XObject& XObject::operator=(const a8::XObject& obj)
|
|
{
|
|
switch (obj.type_) {
|
|
case XOT_SIMPLE:
|
|
{
|
|
if (!value_.x_value) {
|
|
value_.x_value = new a8::XValue();
|
|
} else {
|
|
*value_.x_value = a8::XValue();
|
|
}
|
|
if (obj.value_.x_value) {
|
|
*value_.x_value = *obj.value_.x_value;
|
|
}
|
|
}
|
|
break;
|
|
case XOT_ARRAY:
|
|
{
|
|
if (!value_.array_value) {
|
|
value_.array_value = new std::vector<std::shared_ptr<a8::XObject>>();
|
|
}
|
|
*value_.array_value = *obj.value_.array_value;
|
|
}
|
|
break;
|
|
case XOT_OBJECT:
|
|
{
|
|
if (!value_.object_value) {
|
|
value_.object_value = new std::map<std::string, std::shared_ptr<a8::XObject>>();
|
|
}
|
|
*value_.object_value = *obj.value_.object_value;
|
|
}
|
|
break;
|
|
}
|
|
type_ = obj.type_;
|
|
return *this;
|
|
}
|
|
|
|
a8::XObject& XObject::Move(a8::XObject& a)
|
|
{
|
|
a.type_ = type_;
|
|
a.value_ = value_;
|
|
|
|
type_ = XOT_SIMPLE;
|
|
value_.x_value = {0};
|
|
return *this;
|
|
}
|
|
|
|
bool XObject::ReadFromFile(const std::string& filename)
|
|
{
|
|
std::string data;
|
|
if (!a8::ReadStringFromFile(filename, data)) {
|
|
return false;
|
|
}
|
|
return ReadFromJsonString(data);
|
|
}
|
|
|
|
bool XObject::ReadFromJsonFile(const std::string& filename)
|
|
{
|
|
std::string data;
|
|
if (!a8::ReadStringFromFile(filename, data)) {
|
|
return false;
|
|
}
|
|
return ReadFromJsonString(data);
|
|
}
|
|
|
|
bool XObject::ReadFromJsonString(const std::string& json_data)
|
|
{
|
|
Json::Reader reader;
|
|
Json::Value root;
|
|
if (!reader.parse(json_data, root)) {
|
|
return false;
|
|
}
|
|
JsonValueToXObject(root, *this);
|
|
return true;
|
|
}
|
|
|
|
bool XObject::ReadFromXmlFile(const std::string& filename)
|
|
{
|
|
std::string data;
|
|
if (!a8::ReadStringFromFile(filename, data)) {
|
|
return false;
|
|
}
|
|
return ReadFromXmlString(data);
|
|
}
|
|
|
|
bool XObject::ReadFromXmlString(const std::string& xmldata)
|
|
{
|
|
tinyxml2::XMLDocument xmldoc;
|
|
if (tinyxml2::XML_SUCCESS != xmldoc.Parse(xmldata.data(), xmldata.size())) {
|
|
return false;
|
|
}
|
|
tinyxml2::XMLElement* root = xmldoc.RootElement();
|
|
if (!root) {
|
|
return false;
|
|
}
|
|
XmlElementToXObject(root, *this);
|
|
return true;
|
|
}
|
|
|
|
void XObject::ReadFromUrlQueryString(const std::string& query_string)
|
|
{
|
|
type_ = a8::XOT_OBJECT;
|
|
value_.object_value = new std::map<std::string, std::shared_ptr<a8::XObject>>();
|
|
|
|
std::vector<std::string> params;
|
|
a8::Split(query_string, params, '&');
|
|
for(unsigned int i = 0; i < params.size(); i++){
|
|
int pos = params[i].find('=');
|
|
if(pos > 0){
|
|
std::string key = params[i].substr(0, pos);
|
|
std::string val = params[i].substr(pos + 1, params[i].size() - pos);
|
|
val = a8::UrlDecode(val);
|
|
{
|
|
std::shared_ptr<a8::XObject> xobj_ptr = std::make_shared<a8::XObject>();
|
|
xobj_ptr->type_ = a8::XOT_SIMPLE;
|
|
xobj_ptr->value_.x_value = new a8::XValue(val);
|
|
(*value_.object_value)[key] = xobj_ptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void XObject::ToJsonStr(std::string& data)
|
|
{
|
|
if (type_ == a8::XOT_SIMPLE) {
|
|
switch (value_.x_value->Type()){
|
|
case XVT_INT:
|
|
case XVT_UINT:
|
|
case XVT_FLOAT:
|
|
data.append(value_.x_value->GetString());
|
|
break;
|
|
default:
|
|
data.append("\"" + a8::JsonEscapeString(value_.x_value->GetString()) + "\"");
|
|
break;
|
|
}
|
|
} else if (type_ == a8::XOT_ARRAY) {
|
|
data.push_back('[');
|
|
for (auto& val : *value_.array_value) {
|
|
val->ToJsonStr(data);
|
|
data.push_back(',');
|
|
}
|
|
if (data[data.size() - 1] == ',') {
|
|
data[data.size() - 1] = ']';
|
|
} else {
|
|
data.push_back(']');
|
|
}
|
|
} else if (type_ == a8::XOT_OBJECT) {
|
|
data.push_back('{');
|
|
for (auto& pair : *value_.object_value) {
|
|
data.append("\"" + pair.first + "\":");
|
|
pair.second->ToJsonStr(data);
|
|
data.push_back(',');
|
|
}
|
|
if (data[data.size() - 1] == ',') {
|
|
data[data.size() - 1] = '}';
|
|
} else {
|
|
data.push_back('}');
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string XObject::ToJsonStr()
|
|
{
|
|
std::string data;
|
|
ToJsonStr(data);
|
|
return data;
|
|
}
|
|
|
|
void XObject::ToUrlEncodeStr(std::string& data)
|
|
{
|
|
if (type_ == a8::XOT_OBJECT) {
|
|
for (auto& pair : *value_.object_value) {
|
|
data.append("&" + pair.first + "=" + a8::UrlEncode(pair.second->AsXValue().GetString()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void XObject::ToKVList(std::map<std::string, std::string>& kv_list)
|
|
{
|
|
if (type_ == a8::XOT_OBJECT) {
|
|
for (auto& pair : *value_.object_value) {
|
|
kv_list[pair.first + ""] = pair.second->AsXValue().GetString() + "";
|
|
}
|
|
}
|
|
}
|
|
|
|
void XObject::GetKeys(std::vector<std::string>& keys)
|
|
{
|
|
if (type_ == a8::XOT_OBJECT) {
|
|
for (auto& pair : *value_.object_value) {
|
|
keys.push_back(pair.first);
|
|
}
|
|
}
|
|
}
|
|
|
|
void XObject::JsonValueToXObject(Json::Value& json_val, a8::XObject& xobject)
|
|
{
|
|
Json::ValueType val_type = json_val.type();
|
|
switch (val_type) {
|
|
case Json::ValueType::nullValue:
|
|
{
|
|
xobject.type_ = a8::XOT_SIMPLE;
|
|
xobject.value_.x_value = new a8::XValue();
|
|
}
|
|
break;
|
|
case Json::ValueType::intValue:
|
|
{
|
|
xobject.type_ = a8::XOT_SIMPLE;
|
|
xobject.value_.x_value = new a8::XValue(json_val.asLargestInt());
|
|
}
|
|
break;
|
|
case Json::ValueType::uintValue:
|
|
{
|
|
xobject.type_ = a8::XOT_SIMPLE;
|
|
xobject.value_.x_value = new a8::XValue(json_val.asLargestUInt());
|
|
}
|
|
break;
|
|
case Json::ValueType::realValue:
|
|
{
|
|
xobject.type_ = a8::XOT_SIMPLE;
|
|
xobject.value_.x_value = new a8::XValue(json_val.asDouble());
|
|
}
|
|
break;
|
|
case Json::ValueType::stringValue:
|
|
{
|
|
xobject.type_ = a8::XOT_SIMPLE;
|
|
xobject.value_.x_value = new a8::XValue(json_val.asString());
|
|
}
|
|
break;
|
|
case Json::ValueType::booleanValue:
|
|
{
|
|
xobject.type_ = a8::XOT_SIMPLE;
|
|
xobject.value_.x_value = new a8::XValue(json_val.asBool() ? 1 : 0);
|
|
}
|
|
break;
|
|
case Json::ValueType::arrayValue:
|
|
{
|
|
xobject.type_ = a8::XOT_ARRAY;
|
|
xobject.value_.array_value = new std::vector<std::shared_ptr<a8::XObject>>();
|
|
xobject.value_.array_value->reserve(json_val.size());
|
|
for (unsigned int i = 0; i < json_val.size(); ++i) {
|
|
std::shared_ptr<a8::XObject> xobject_ptr = std::make_shared<a8::XObject>();
|
|
JsonValueToXObject(json_val[i], *xobject_ptr);
|
|
xobject.value_.array_value->push_back(xobject_ptr);
|
|
}
|
|
}
|
|
break;
|
|
case Json::ValueType::objectValue:
|
|
{
|
|
xobject.type_ = a8::XOT_OBJECT;
|
|
xobject.value_.object_value = new std::map<std::string, std::shared_ptr<a8::XObject>>();
|
|
for (std::string& key : json_val.getMemberNames()) {
|
|
std::shared_ptr<a8::XObject> xobject_ptr = std::make_shared<a8::XObject>();
|
|
JsonValueToXObject(json_val[key], *xobject_ptr);
|
|
(*xobject.value_.object_value)[key] = xobject_ptr;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
assert(false);
|
|
abort();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void XObject::XmlElementToXObject(tinyxml2::XMLElement* xml_ele, a8::XObject& xobject)
|
|
{
|
|
//初始化对象
|
|
{
|
|
xobject.type_ = a8::XOT_OBJECT;
|
|
xobject.value_.object_value = new std::map<std::string, std::shared_ptr<a8::XObject>>();
|
|
{
|
|
std::shared_ptr<a8::XObject> xobj_ptr = std::make_shared<a8::XObject>();
|
|
xobj_ptr->type_ = a8::XOT_ARRAY;
|
|
xobj_ptr->value_.array_value = new std::vector<std::shared_ptr<a8::XObject>>();
|
|
(*xobject.value_.object_value)[std::string("attr_names")] = xobj_ptr;
|
|
}
|
|
{
|
|
std::shared_ptr<a8::XObject> xobj_ptr = std::make_shared<a8::XObject>();
|
|
xobj_ptr->value_.x_value = new a8::XValue(xml_ele->GetText());
|
|
(*xobject.value_.object_value)[std::string("node_value")] = xobj_ptr;
|
|
}
|
|
}
|
|
//读取节点所有属性已经属性名 attr_names:存储所有的属性名
|
|
{
|
|
const tinyxml2::XMLAttribute* attr = xml_ele->FirstAttribute();
|
|
while (attr) {
|
|
{
|
|
std::shared_ptr<a8::XObject> xobj_ptr = std::make_shared<a8::XObject>();
|
|
xobj_ptr->value_.x_value = new a8::XValue(attr->Value());
|
|
(*xobject.value_.object_value)[std::string("attrs.") + attr->Name()] = xobj_ptr;
|
|
}
|
|
{
|
|
std::shared_ptr<a8::XObject> xobj_ptr = std::make_shared<a8::XObject>();
|
|
xobj_ptr->value_.x_value = new a8::XValue(attr->Name());
|
|
(*xobject.value_.object_value)[std::string("attr_names")]->value_.array_value->push_back(xobj_ptr);
|
|
}
|
|
attr = attr->Next();
|
|
}
|
|
}
|
|
//读取所有子节点并按 child_node.属性名 分类存储 child_nodes:存储所有的子节点
|
|
{
|
|
std::shared_ptr<a8::XObject> child_nodes_ptr = std::make_shared<a8::XObject>();
|
|
child_nodes_ptr->type_ = a8::XOT_ARRAY;
|
|
child_nodes_ptr->value_.array_value = new std::vector<std::shared_ptr<a8::XObject>>();
|
|
(*xobject.value_.object_value)["child_nodes"] = child_nodes_ptr;
|
|
|
|
std::map<std::string, std::vector<std::shared_ptr<a8::XObject>>*> child_classes_hash;
|
|
tinyxml2::XMLElement* child_node = xml_ele->FirstChildElement();
|
|
while (child_node) {
|
|
std::shared_ptr<a8::XObject> xobj_ptr = std::make_shared<a8::XObject>();
|
|
XmlElementToXObject(child_node, *xobj_ptr);
|
|
child_nodes_ptr->value_.array_value->push_back(xobj_ptr);
|
|
{
|
|
auto itr = child_classes_hash.find(child_node->Name());
|
|
if (itr != child_classes_hash.end()) {
|
|
itr->second->push_back(xobj_ptr);
|
|
} else {
|
|
child_classes_hash[child_node->Name()] = new std::vector<std::shared_ptr<a8::XObject>>({xobj_ptr});
|
|
}
|
|
}
|
|
|
|
child_node = child_node->NextSiblingElement();
|
|
}
|
|
//按属性分类
|
|
for (auto& pair : child_classes_hash) {
|
|
std::shared_ptr<a8::XObject> xobj_ptr = std::make_shared<a8::XObject>();
|
|
xobj_ptr->type_ = a8::XOT_ARRAY;
|
|
xobj_ptr->value_.array_value = pair.second;
|
|
(*xobject.value_.object_value)[std::string("child_node.") + pair.first] = xobj_ptr;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void XObject::ConvertObject()
|
|
{
|
|
type_ = XOT_OBJECT;
|
|
value_.object_value = new std::map<std::string, std::shared_ptr<a8::XObject>>();
|
|
}
|
|
|
|
void XObject::ConvertArray()
|
|
{
|
|
type_ = XOT_ARRAY;
|
|
value_.array_value = new std::vector<std::shared_ptr<a8::XObject>>();
|
|
}
|
|
|
|
}
|