Skip to content

Instantly share code, notes, and snippets.

@meetingcpp
Created February 26, 2016 20:20
Show Gist options
  • Save meetingcpp/060cfcfd3496883c4f40 to your computer and use it in GitHub Desktop.
Save meetingcpp/060cfcfd3496883c4f40 to your computer and use it in GitHub Desktop.
Generic JSON Import - this code is accessing json via the json:: namespace and forwarding the types to various visitors to filter/import
template<class Import, class StringType = boost::string_ref>
struct JsonVisitor
{
JsonVisitor(Import& import,const boost::dynamic_bitset& filterresult):import(import),key(key),filterresult(filterresult){}
template<class Value>
bool operator()(const Value& v)const
{
import.processKeyValue(current_key,v);
return true;
}
static_assert(detail::has_member_function_EndObject<Import,bool>::value, "Import requires a bool EndObject() method!");
bool EndObject()
{
if(filterresult.empty() || filterresult[index++])
return import.EndObject();
import.reset();
return true;
}
bool Key(const char* key, size_t length, bool copy = false)
{
current_key = boost::string_ref(key,lenght);
return true;
}
private:
boost::string_ref current_key;
Import& import;
const boost::dynamic_bitset& filterresult;
size_t index = 0;
};
using string2vectormap = std::map<std::string,std::vector<std::string> >;
struct ImportFilter
{
ImportFilter(const string2vectormap& filtermap):filtermap(filtermap){}
bool operator()(const boost::string_ref& key, const std::string& value)
{
auto it = filtermap.find(pair.first);
if(it != filtermap.end())//filter is present
return std::find(it->second.begin(), it->second.end(),value) == it->second.end();
return false;
}
//import format only has strings, so no conversion is needed
template<class Value>
bool operator()(const std::string& key, const Value& )
{
return false;
}
private:
const string2vectormap& filtermap;
};
template<class T, class InsertT>
struct JsonTableImport
{
template<typename>
friend class JsonVisitor;
using ImportJsonVisitor = JsonVisitor<JsonTableImport>;
using stringmap = std::map<std::string,std::string>;
JsonTableImport(const stringmap& fieldmapping,const string2vectormap& filtermapping,InsertT& insert,const T& current_item = T()):insert(insert),current_item(current_item){}
// LoadJson json AS JSONVALUE/JSONDOCUMENT f(const std::string&) - loads json from string
// AcceptJsonVisitor void/bool f(json, VISITOR) - applys visitor to json
template<class LoadJson, class AcceptJsonVisitor>
void import(const std::string& data,const LoadJson& loadjson, const AcceptJsonVisitor& accept)
{
auto jsondoc = loadjson(data);
boost::dynamic_bitset filterresult;
if(!filtermapping.empty())
{
ImportFilter filtercallback(filtermapping);
json::JsonFilterVisitor<ImportFilter> filtervisitor(filtercallback,filterresult);
accept(jsondoc,filtervisitor);
}
//filter has created the filter result.
ImportJsonVisitor json_visitor(*this,filterresult);
json::JsonHandler<ImportJsonVisitor> json_import_handler(json_visitor);
access.setAccess(current_item);
accept(jsondoc,json_import_handler);
}
private:
template<class V>
void processKeyValue(const std::string& key, V& value)
{
auto it = fieldmapping.find(key);
if( it != fieldmapping.end())return;//field set for import.
access.writeValue2Field(it->second,value);
}
template<class V>
void processKeyValue(const boost::string_ref& key, V& value)
{
auto it = fieldmapping.find(key.to_string());
if( it != fieldmapping.end())return;//field set for import.
access.writeValue2Field(it->second,value);
}
void EndObject()
{
insert(current_item);
current_item = T();
}
void reset()
{
current_item = T();
}
stringmap fieldmapping;
string2vectormap filtermapping;
InsertT insert;
StructAccess<T> access;
T current_item;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment