抽取ROS中的未知消息内容以及Sqlite3 使用JSON1扩展的方法以及示例--命令行模式

        Sqlite3 在3.09版本开始就带了JSON扩展,刚开始的版本需要使用源代码编译加上相应的参数来开启JSON支持。经实际调研测试发现Ubuntu16.04开始之后Ubuntu库里面的sqlite3已经默认开启了JSON支持(具体查看我的博客),直接使用apt-get install sqlite3就可以安装sqlite3了,也可以直接使用json。

       那么Json在sqlite3中是如何使用的呢?其实很简单,Sqlite3的JSON1扩展插件是通过提供一系列函数来实现Json格式数据的插入、查询、更新操作的。考虑到Sqlite3支持的数据类型,我们确定,要想使用JSON1扩展,可以设置一个TEXT字段(一列)用来存储json数据,然后就可以通过提供的函数执行插入、查询、更新等操作。

示例:

1. 创建表:

这里直接使用我们建的表--observe,我们在micros中使用的数据统一封装模型。因为项目中各种消息类型不一,而存储的时候甚至不知道要处理的消息长什么样子,而对于未知类型的数据我们是无法存储,也就是说我们要先建表,然后才存储数据,而对于未知类型的数据,我们无法在数据到来之后再动态建表,而micros中各种新数据类型在未知时间以未知类型出现是很常见的。这是目前结构化数据库或者说关系性数据库面临的一个困局。在早期,我们还没有调研json的时候直接设计了一个统一的数据封装模型:把所有类型数据共有的字段抽出来,而把具体的数据放到了一个char[]里面,而检索呢,显然只能对共有字段开展,而无法对char[]中的数据进行检索。

在后面,我们使用了xml,后面有需要对xml进行检索,在设计方案的时候进行调研,顺便调研到了json扩展这个事情。于是决定在原来的表上增加一个字段,使用json格式来存储原来char[]中的部分数据,这样就可以提供所谓的二次检索(使用sql和json扩展函数)了。下面就是我们增加了一个字段content的建表语句:

CREATE TABLE IF NOT EXISTS observe(id INTEGER PRIMARY KEY AUTOINCREMENT,
swarmID INTERGER NOT NULL, taskName TEXT NOT NULL, actorName TEXT NOT NULL,
robotID INTEGER NOT NULL, timeStamp TEXT NOT NULL, dataType TEXT NOT NULL,
offset INTERGER NOT NULL, size INTERGER NOT NULL, fileName TEXT NOT NULL, content TEXT,
positionZ REAL NOT NULL);

2. 添加数据:

除了content字段之外的数据添加与原来相同,而content相对麻烦点,首先要把msg<T> t (不管什么类型的msg)解析出来并转成json格式,然后作为text(就是C++  中的string)给content。

而t中的数据解析出来,就用到了我们调研到的ROS 消息机制提供的ros::message_operations::Printer<T> p,借助它,我们将t的数据获取到并转换格式。

int getLevel(std::string line)
{
    return 1+line.find_first_not_of(" ")/2;
}

bool isNormalPrefix(std::string line)
{
    if(line.find_last_of(": ")==(line.length()-2)) return true;
    else return false;
}

bool isArrayPrefix(std::string line)
{
    if(line.find_last_of("[]")==(line.length()-2))
    {
        return true;
    }
    else return false;
}
bool hasChildren(int i, const std::vector<int> level)
{
    if(i>=level.size()) {
        ROS_ERROR("The index is out of the size of the vector level!");
        exit(-1);
    }
    else if(i==level.size()-1) //the last node
    {
        return false;
    }
    else
    {
        if(level[i]<level[i+1]) return true;
        else return false;
    }

}
bool endWith(std::string substr, std::string str)
{
    int subLen = substr.length();
    int len = str.length();

    if(subLen<=len)
    {
       std::string tmp = str.substr(len-subLen,subLen) ;
       if(tmp==substr) return true;
    }
    return false;
}

std::string& getContent(std::string &line)
{
    if(line.empty()) return line;

    line.erase(0,line.find_first_not_of(" "));
    if(endWith(": ",line)) line.erase(line.size()-2,1);
    line.erase(line.find_last_not_of(" ")+1);
    return line;
}

int getKV(std::string &key, std::string &value, std::string line)
{
    if(line.empty()) return 0;
    std::string::size_type pos_begin = line.find_first_not_of(": ");
    std::string::size_type dlm_pos ;
    std::string tmp;


    dlm_pos = line.find(": ",pos_begin);

    if(dlm_pos==std::string::npos)
    {
        key = line;
       // value = NULL;
      //  std::cout<<"key:"<<key<<", value: NULL"<<std::endl;
        return -1;//no ": " in line;
    }
    else if(dlm_pos == line.length()-2)
    {
        key = line.substr(pos_begin,dlm_pos-pos_begin);
        value = "";
       // std::cout<<"key:"<<key<<", value:"<<value<<std::endl;
        return 0;
    }
    else
    {
        key = line.substr(pos_begin,dlm_pos-pos_begin);
        value = line.substr(dlm_pos+2);
        dlm_pos = value.find(": ",0);
       // std::cout<<"key:"<<key<<", value:"<<value<<std::endl;
        if(dlm_pos!=std::string::npos)
        {
            return -2;// there are many ": " in line
        }
        else{
            return 1;
        }

    }
    return -1;
}

int getNextCurLevel(int curLevel, int startPos, std::vector<int> levelVec)
{
    if(startPos>=levelVec.size())
    {
        ROS_ERROR("start1 position out of the vector size!");
        exit(-1);
    }
    else
    {
        for(int i= startPos;i<levelVec.size();i++)
        {
            if(levelVec[i]==curLevel) return i;
        }
    }
    return -1;
}



int getChildrenPos(std::vector<int> &poses, int curLevel,int startPos, int endPos, std::vector<int> levelVec)
{
    poses.clear();

    if(startPos>endPos)
    {
        ROS_ERROR("start2 position is larger than end position!");
        exit(-1);
    }


    if(startPos>=levelVec.size() || endPos>levelVec.size())
    {
        ROS_ERROR("start/end position is out of the size of the vector!");
        exit(-1);
    }
    for(int curPos =startPos;curPos<endPos;curPos++)
    {
        if(levelVec[curPos]==curLevel+1)
        {
            poses.push_back(curPos);
        }
    }
    return poses.size();
}
template<typename T>
std::string toJSON(T aMsg)
{
    std::string msg2json = "{ ";
    std::vector<int> levels;
    std::vector<bool> beOut;
    std::vector<std::string> values;
    std::vector<bool> over;
    int num,curLevel=1,maxLevel;
    int startPos=0,curPos=0,endPos=0;
    ros::message_operations::Printer<T> p;
    std::ostringstream ss;
    p.stream(ss, "", aMsg);
    std::string data = ss.str();
    //std::cout<<data<<"........"<<std::endl;


    boost::regex reg("\n");
    boost::sregex_token_iterator it(data.begin(), data.end(), reg, -1);
    boost::sregex_token_iterator end;

    while(it != end)
    {
       std::string t = *it;
       //std::cout<<"line content : "<<t<<std::endl;
       int tmpLevel = getLevel(t);
       if(tmpLevel>maxLevel) maxLevel=tmpLevel;
      // std::cout<<"level : "<<tmpLevel<<std::endl;
       levels.push_back(tmpLevel);
       over.push_back(false);
       std::string tmp = getContent(t);
     //  std::cout<<"content : "<<tmp<<std::endl;
       values.push_back(tmp);
       it++;
    }
    num = values.size();

    for(int i=0;i<num;i++){
        beOut.push_back(!hasChildren(i,levels));
       // std::cout<<"value["<<i<<"]: "<<values[i]<<", level["<<i<<"]: "<<levels[i]<<", beOut["<<i<<"]: "<<beOut[i]<<std::endl;
    }

    curLevel =1;
    startPos = getNextCurLevel(curLevel,0,levels);

    for(curLevel=1;curLevel<=maxLevel;curLevel++)
    {
       // std::cout<<"curLevel :"<<curLevel<<std::endl;
       // std::cout<<"curLevel startPos : "<<startPos;
        while(startPos<=(levels.size()-1))
        {

            if(startPos+1>levels.size()-1) break;
            endPos = getNextCurLevel(curLevel,startPos+1,levels);
            if(endPos == -1 ) endPos = num;
            std::vector<int> poses;
            //std::cout<<"endPos: "<<endPos<<std::endl;
            int childNum = getChildrenPos(poses, curLevel, startPos, endPos, levels);
            for(int i =0;i<childNum; i++)
            {
                values[poses[i]] =  values[startPos]+"/"+values[poses[i]];
                over[poses[i]] = true;
            }
            over[startPos] = true;
            startPos = endPos;
            //std::cout<<"startPos:-->"<<startPos<<std::endl;


        }
       startPos = 0;

    }

   /* for(int i=0;i<num;i++){
       // beOut.push_back(!hasChildren(i,levels));
        std::cout<<"value["<<i<<"]: "<<values[i]<<std::endl;//<<", level["<<i<<"]: "<<levels[i]<<", beOut["<<i<<"]: "<<beOut[i]<<std::endl;
    }*/

    //if value contains "[]", then ignore the value
    for(int i=0;i<num;i++)
    {
        if(beOut[i])
        {
            if(values[i].find("[]")!=std::string::npos)
            {
                beOut[i] = false;
            }
            else
            {
                std::string key,value;
                getKV(key,value,values[i]);
               // msg2json = msg2json+values[i]+",";
                 msg2json = msg2json+"\""+key+"\": "+"\""+value+"\""+ ",";
            }
        }
    }


    msg2json=msg2json.substr(0,msg2json.length()-1)+"}";
    return msg2json;
}

上述代码可以从msg<T> t 中提取出非数组部分,然后组成最简单的json格式,后面就可以将这个json格式作为content的内容,正常写入数据库了。

3. sqlite3的JSON1扩展提供的函数

Json 函数

json(string) 函数会返回一个json对象。

sqlite> select json('{"first":"test", "second":"haha"}');
{"first":"test","second":"haha"}

Json_Object 函数

json_object(key1, value1, key2, value2…) 将json的字段和值传入,会返回json对象。

sqlite> select json_object('first', 'test', 'second', 'haha');
{"first":"test","second":"haha"}

sqlite> select json_object('jsob', json('{"first":"test","second":"haha"}'),'jso
b2', json('{"frist":"test","second":"haha"}'));
--------------------------------------------------
{"jsob":{"first":"test","second":"haha"},"jsob2":{"frist":"test","second":"haha"
}}

在json_object中的参数也可以是json对象,两个函数可以嵌套使用。
Json_Array 函数

json_Array(value1, value2…) 函数会返回一个数组。

sqlite> select json_array(1,2,3,4);
[1,2,3,4]

如果传入的是 json 对象,就会返回json数组。

sqlite> select json_array(json_object('first','test','second','haha'));
[{"first":"test","second":"haha"}]

Json_Array_Length 函数

json_array_length(json),返回指定的数组的长度。

sqlite> select json_array_length('[1,2,3,4]');
4

sqlite> select json_array_length('{"one":[1,2,3]}', '$.one');
3

path: $ 代表前面的这个json对象,one则是字段名。返回 one 的长度。

sqlite> select json_array_length('{"one":[1,2,3], "two": "3"}', '$.two');
0

因为 two 中的只是 3 这个字符,并不是数组,所以返回 0。

Json_Extract 函数

json_extract(json, path, …) 函数的功能是截取 json 中的 value 值。

sqlite> select json_extract('{"a":2, "c":[4,5,{"f":7}]}', '$.c');
--------------------------------------------------------
[4,5,{"f":7}]

可以看到有一个长的 json 对象,分别有 a,b,c 三个字段,c 的值为一个数组,数组里有 4,5和一个 json 对象。截取 json 中的 c 字段。

sqlite> select json_extract('{"a":2, "c":[4,5,{"f":7}]}', '$.c[0]');
---------------------------------------------------------
4
sqlite> select json_extract('{"a":2, "c":[4,5,{"f":7}]}', '$.c[2]');
---------------------------------------------------------
{"f":7}

因为 c 字段的值是数组,所以可以这样去取数组中的值。

sqlite> select json_extract('{"a":2, "c":[4,5,{"f":7}]}', '$.c[2].f');
7

同理,也可以这样取 f 字段的value。

sqlite> select json_extract('{"a":2, "c":[4,5,{"f":7}]}', '$.a','$.c');
---------------------------------------------------------
[2,[4,5,{"f":7}]]

同时截取两个或以上的值,则返回数组。
Json_Insert 函数

json_insert(json, path, value) 函数是将一个 json 字段插入 json 对象中,最后返回插入后的 json 对象。

sqlite> select json_insert('{"a":2, "c":4}', '$.a', 99);
{"a":2,"c":4}

sqlite> select json_insert('{"a":2, "c":4}', '$.b', 99);
{"a":2,"c":4,"b":99}

这个函数会将未出现的字段插入到 json 对象的末尾,如果是已有的字段,则不会修改。
Json_Replace 函数

json_replace(json, path, value…) 这个函数顾名思义就是将 json 中原来字段的值替换成我们设置的值。

sqlite> select json_replace('{"a":2, "c":4}', '$.a', 99);
{"a":99,"c":4}
sqlite> select json_replace('{"a":2, "c":4}', '$.b', 99);
{"a":2,"c":4}

与 json_insert 相对的,这个函数只能替换,不能添加。

Json_Set 函数

json_set(json, path, value…) 函数拥有 json_insert 和 json_replace 两个的功能,既能修改字段的值,也能添加字段。

sqlite> select json_set('{"a":2, "c":4}', '$.b', 99);
{"a":2,"c":4,"b":99}
sqlite> select json_set('{"a":2, "c":4}', '$.a', 99);
{"a":99,"c":4}
 

发布了71 篇原创文章 · 获赞 93 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/jinking01/article/details/100195333