zoukankan      html  css  js  c++  java
  • Poco::JSON::Array 中object 设置preserveInsertionOrder 时,stringify出错-->深入解析

    在使用poco version 1.6.0时 Poco::JSON::Array 在object  设置preserveInsertionOrder =true 时

    调用 array.stringify出错.

     

    在使用poco::json 输出字符串

        std::string str1 = "
    ";
        std::string str2 = "
    ";
        Poco::JSON::Object obj1, obj2;
        obj1.set("payload", str1);
        obj2.set("payload", str2);
        std::ostringstream oss1, oss2;
        Poco::JSON::Stringifier::stringify(obj1, oss1);
        Poco::JSON::Stringifier::stringify(obj2, oss2);
    
        string srxxx=oss1.str()//正常输出...

    poco::json::array 输出 字符串:

    Object jObj2(true);
        
        std::string  strValue2="[{"backspace1":"bs2222","1backspace1":"1bs2222"},{"te1":"t1","t2":"t2"}]";
        jObj2.set("car", "这是中文abc@qwe.com1231");
        jObj2.set("baz", "fas");
    
        std::stringstream ss2222;
        jObj2.stringify(ss2222);
        strxxx.clear();
        strxxx=CMyCodeConvert::Gb2312ToUtf8(ss2222.str());//gbk->utf8
        
        Object jObj3(true);
    
        jObj3.set("5", "2");
        jObj3.set("2", "2");
    
        Object jObj4(false);
    
        jObj4.set("51", "2");
        jObj4.set("21", "2");
        
    
            Poco::JSON::Array  array1;
    
    
    
    
            //array1.add(resultxxx);
            array1.add(jObj2);
            array1.add(jObj3);
            array1.add(jObj4);
            //jObj.set("arrar",array1);
    
    
    
            std::stringstream ssArray1;
            Stringifier::stringify(array1,ssArray1);
            //array1.stringify(ssArray1);
            std::string strArray1=ssArray1.str();//->>>>>>输出字符串出错.

    but run time is error

    追踪代码发现:

    JSONsrcObject.cpp:

     

    Object(bool preserveInsertionOrder = false); //在map 中排序 ,输出时按字母大小顺序.
    /// Default constructor. If preserveInsertionOrder, object
    /// will preserve the items insertion order. Otherwise, items
    /// will be sorted by keys.

    preserveInsertionOrder = false 这个我比较反感,因为之前用jsoncpp 处理 某些东东时,因为输出时入 输入的json顺序不 一致  走了不少弯路.

    所以  preserveInsertionOrder = true  是我的爱 .

    Stringifier::stringify(array1,ssArray1); 

    ----->

    JSONsrcStringifier.cpp:

    else if ( any.type() == typeid(Array) )
    {
    const Array& a = any.extract<Array>();
    a.stringify(out, indent == 0 ? 0 : indent, step);
    }

    --->

    if ( any.type() == typeid(Object) )
    {
    const Object& o = any.extract<Object>();
    o.stringify(out, indent == 0 ? 0 : indent, step);
    }

    --->

    JSONsrcObject.cpp:

    void Object::stringify(std::ostream& out, unsigned int indent, int step) const
    {
    if (step < 0) step = indent;

    if(!_preserveInsOrder)
    doStringify(_values, out, indent, step);  // 不用代码添加顺序 ,则使用map窗口..jsoncpp也是map
    else
    doStringify(_keys, out, indent, step);//保留原有代码添加顺序, 则使用 std::deque<Dynamic::Var*> KeyPtrList
    }

    --->

     PocoJSONObject.h

    template <typename C>
    void doStringify(const C& container, std::ostream& out, unsigned int indent, unsigned int step) const
    {
     ....

    Stringifier::stringify(getKey(it), out); //这儿   getKey(it), 出了问题
    out << ((indent > 0) ? " : " : ":");

    Stringifier::stringify(getValue(it), out, indent + step, step);

    ...

    }

    JSONsrcObject.cpp:

    const std::string& Object::getKey(KeyPtrList::const_iterator& iter) const
    {
    ValueMap::const_iterator it = _values.begin();
    ValueMap::const_iterator end = _values.end();
    for (; it != end; ++it)
    {
    if (it->second == **iter) return it->first;
    }

    throw NotFoundException((*iter)->convert<std::string>());  //----->这儿报错
    }

    --->

    Object.cpp中:


    void Object::set(const std::string& key, const Dynamic::Var& value)
    {
    _values[key] = value;
    if (_preserveInsOrder)
    {
    KeyPtrList::iterator it = _keys.begin();
    KeyPtrList::iterator end = _keys.end();
    for (; it != end; ++it)
    {
    if (key == **it) return;
    }
    _keys.push_back(&_values[key]);  //->这儿的内存地址发生了变化.
    }
    }

    示例代码中:

     array1.add(jObj2);  -->Object 转到 (const Dynamic::Var& value)时

    FoundationincludePocoDynamicVar.h:

    Var(const T& val)
    /// Creates the Var from the given value.
    #ifdef POCO_NO_SOO
    : _pHolder(new VarHolderImpl<T>(val))  --->>>发生了拷贝所以内存地址变化了.
    {
    }

    后面在 https://github.com/pocoproject/poco/commit/3553a86d608321c1a06262c721aa766f1808cf2c 

    作者说

    const std::string& Object::getKey(KeyPtrList::const_iterator& iter) const 中

    if (&it->second == *iter) return it->first;  

     

    改成

    if (it->second == **iter) return it->first;

    注意 这个==是

    poco开发版本地址:

    https://github.com/pocoproject/poco/blob/develop/JSON/include/Poco/JSON/Object.h

    https://github.com/pocoproject/poco/blob/develop/JSON/src/Object.cpp

    以下只贴出了 重要更新的代码.

    
    
    //
    // Object.h

    如果是vs08的环境:

    inline const Dynamic::Var& Object::getValue(KeyPtrList::const_iterator& it) const
    {

    return _values.at(**it);  //map.at 是C++ 11的标准,这儿不支持.

    }

    改成:

    inline const Dynamic::Var& Object::getValue(KeyPtrList::const_iterator& it) const
    {
    const std::string & strKey=**it;
    ValueMap ::const_iterator iter = _values.find(strKey);
    if(iter!=_values.end())
    return iter->second;

    throw NotFoundException(strKey);
    }

     
    //
    // Object.cpp
    //
    // $Id$
    ............
    
    void Object::stringify(std::ostream& out, unsigned int indent, int step) const
    {
        if (step < 0) step = indent;
    
        if(!_preserveInsOrder)
            doStringify(_values, out, indent, step);
        else
            doStringify(_keys, out, indent, step);
    }
    
    
    const std::string& Object::getKey(KeyPtrList::const_iterator& iter) const
    {
        ValueMap::const_iterator it = _values.begin();
        ValueMap::const_iterator end = _values.end();
        for (; it != end; ++it)
        {
            if (it->first == **iter) return it->first;
        }
    
        throw NotFoundException(**iter);
    }
    
    
    void Object::set(const std::string& key, const Dynamic::Var& value)
    {
        std::pair<ValueMap::iterator, bool> ret = _values.insert(ValueMap::value_type(key, value));
        if (_preserveInsOrder)
        {
            KeyPtrList::iterator it = _keys.begin();
            KeyPtrList::iterator end = _keys.end();
            for (; it != end; ++it)
            {
                if (key == **it) return;
            }
            _keys.push_back(&ret.first->first);
        }
    }
    
    
    

    测试结果:

    Object jObj2(true);//-------->use preserveInsertionOrder=true
    
    jObj2.set("car", "这是中文abc@qwe.com1231");
    jObj2.set("baz", "fas");
    jObj2.set("baz1", "fas");
    jObj2.set("1baz11", "fas");
    Poco::JSON::Array array1;
    array1.add(jObj2);
    
    std::ostringstream oss122;
    array1.stringify(oss122);
    std::string fdsafsa=oss122.str();
    
    std::cout<<"array1="<<fdsafsa<<std::endl;
    //输出:[{"car":"这是中文abc@qwe.com1231","baz":"fas","baz1":"fas","1baz11":"fas"}]

       本以为到这儿就已经结束了....

      然而我错了...

      上篇附笔中:

      poco json 中文字符,抛异常JSON Exception -->iconv 转换 备忘录。

      http://www.cnblogs.com/bleachli/p/4646092.html

      中的 suite()作下改变:

      

    std::string  suite()
    {
    
    
        std::string json = "";
            //"{"
            //""id": 1123,"
            //""jsonrpc": " 123.abc@hello.com,大圣归来.. ","
            //""total": 2,"
            //""result": "
            //"["
            //"{"
            //""id": null,"
            //""picture": "http://placehold.it/32x32","
            //""name": "这是中文测试.Crossman","
            //""about": "《西游记之大圣归来》是根据中国传统神话故事进行拓展和演绎的3D动画电影.xxxx Consectetuer suscipit volutpat eros dolor .","
            //""friends": "
            //"["
            //"{"
            //"},"
            //"{"
            //""id": 2,"
            //""name": "Bailey Oldridge2""
            //"},"
            //"{"
            //""id": 3,"
            //""name": "Makayla Campbell3""
            //"}"
            //"]"
            //"},"
            //"{"
            //""id": 2,"
            //""picture": "http://placehold.it/32x32","
            //""name": "2中名 欢迎 ","
            //""about": "2北京你好 dolor .","
            //""friends": "
            //"["
            //"]"
            //"}"
            //"]"
            //"}";
    
    
        std::string strUtf8=GetJsonSource(true);
    
    
        Parser parser;
        Var result;
    
        try
        {
            result = parser.parse(strUtf8);//json转换...
        }
        catch(JSONException& jsone)
        {
            std::cout << jsone.message() << std::endl;
            return "result==NULL";
        }
        
    
        Object::Ptr object = result.extract<Object::Ptr>();
        int nObjectSize=object->size();
    
        //assert(object->size() > 0);
        DynamicStruct ds = *object;
    
        //遍历...
        for(DynamicStruct::Iterator  itBegin=ds.begin();itBegin!=ds.end();itBegin++)
        {
            //std::string strvalue=itBegin;
            //Var var= itBegin->second;
            //std::cout<<"type:"<<var.type()<<std::endl;
    
            std::cout<<"K:"  << itBegin->first << " , value: " <<CMyCodeConvert::Utf8ToGb2312( itBegin->second.toString()) << std::endl;
        }
    
        std::cout<<std::endl<<std::endl<<std::endl;
        std::cout<<"+++++++++++++++++++++++++++++++++++++++++++++++++++"<<std::endl;
    
    
        json="";
    
        std::string strlation1xxxx;
        std::string strjstostring=strUtf8;
        std::string strTemp;
        std::string strKey;
    
    
    
    
        //std::string strKey="id";
    
        //key 是否存在
        strKey="id";
        if(object->has(strKey))
        {
            strTemp=CMyCodeConvert::Utf8ToGb2312( object->get(strKey).toString());
            std::cout<<"object->get("<<strKey<<")="<<strTemp<<std::endl;
        }
    
        strKey="id2232";
        if(object->has(strKey))
        {
            strTemp=CMyCodeConvert::Utf8ToGb2312( object->get(strKey).toString());
    
            std::cout<<"object->get("<<strKey<<")="<<strTemp<<std::endl;
        }
    
        strKey="jsonrpc";
        if(object->has(strKey))
        {
            strTemp=CMyCodeConvert::Utf8ToGb2312( object->get(strKey).toString());
    
            std::cout<<"object->get("<<strKey<<")="<<strTemp<<std::endl;
    
            std::string strxxx;
            
            std::cout<<"jsonrpc 编码:"<<std::endl;
            std::string strxxxx=strTemp;
            for(int nxxx=0;nxxx<strxxxx.size();++nxxx)
            {
                unsigned char chTemp=strxxxx[nxxx];
                std::string strTemp=Poco::format("%hX",(unsigned short )chTemp);
                strTemp+=" ";
                //std::cout<<strTemp;
            }
    
            std::cout<<std::endl;
    
            //strjstostring+=strTemp;
    
    
            std::cout<<"object333->get("<<strKey<<")="<<strTemp<<std::endl;
        }
    
        strKey="total";
        if(object->has(strKey))
        {
            strTemp=CMyCodeConvert::Utf8ToGb2312( object->get(strKey).toString());
    
            std::cout<<"object->get("<<strKey<<")="<<strTemp<<std::endl;
        }
    
    
        strKey="result";
        if(object->has(strKey))
        {
            strTemp=CMyCodeConvert::Utf8ToGb2312( object->get(strKey).toString());
    
            std::cout<<"object->get("<<strKey<<")="<<strTemp<<std::endl;
    
                
            Var  vResult=object->get("result");
    
            Poco::JSON::Array::Ptr arrayResult = object->getArray("result");
            Poco::JSON::Array::Ptr arr22222 = vResult.extract<Poco::JSON::Array::Ptr>();
    
            Poco::Dynamic::Array dsarrayResult = *arrayResult;
    
            std::cout<<"arr22222->size()"<<arr22222->size()<<std::endl;
            std::cout<<"arrayResult->size()"<<arrayResult->size()<<std::endl;
            std::cout<<"arrayResult->size()"<<dsarrayResult.size()<<std::endl;
    
    
            for(int nIndex=0;nIndex<arrayResult->size();++nIndex)
            {
                Object::Ptr object = arrayResult->getObject(nIndex);
    
    
                strKey="id";
                if(object->has(strKey))
                {
                    strTemp="";
                    if(!object->get(strKey).isEmpty())
                    {
                        strTemp=CMyCodeConvert::Utf8ToGb2312( object->get(strKey).toString());
    
                        std::cout<<"object->get("<<strKey<<")="<<strTemp<<std::endl;
                    }
    
                }
    
                strKey="picture";
                if(object->has(strKey))
                {
                    strTemp=CMyCodeConvert::Utf8ToGb2312( object->get(strKey).toString());
    
                    std::cout<<"object->get("<<strKey<<")="<<strTemp<<std::endl;
                }
    
                strKey="name";
                if(object->has(strKey))
                {
                    strTemp=CMyCodeConvert::Utf8ToGb2312( object->get(strKey).toString());
    
                    std::cout<<"object->get("<<strKey<<")="<<strTemp<<std::endl;
                }
    
                strKey="about";
                if(object->has(strKey))
                {
                    strTemp=CMyCodeConvert::Utf8ToGb2312( object->get(strKey).toString());
    
                    std::cout<<"object->get("<<strKey<<")="<<strTemp<<std::endl;
                }
    
                strKey="friends";
                if(object->has(strKey))
                {
                    strTemp=object->get(strKey).toString();
    
                    std::cout<<"object->get("<<strKey<<")="<<strTemp<<std::endl;
    
                    Poco::JSON::Array::Ptr arrayFriends = object->getArray(strKey);
                    for(int nIndex=0;nIndex<arrayFriends->size();++nIndex)
                    {
                        Object::Ptr objectFriends = arrayFriends->getObject(nIndex);
                        DynamicStruct dsTemp = *objectFriends;
    
                        for(DynamicStruct::Iterator  itBegin=dsTemp.begin();itBegin!=dsTemp.end();itBegin++)
                        {
                            std::cout<<"K:"  << itBegin->first << " , value: " << CMyCodeConvert::Utf8ToGb2312(itBegin->second.toString() )<< std::endl;
                        }
    
                    }
                }
    
    
    
                std::cout<<std::endl<<std::endl<<std::endl;
                std::cout<<"+++++++++++++++++++++++++++++++++++++++++++++++++++"<<std::endl;
    
                std::cout<<std::endl<<std::endl<<std::endl;
    
            }
    
    
    
    
        }
    
        return strjstostring;
    }

    GetJsonSource()代码:

    std::string GetJsonSource(bool bUtf8)
    {
        bool bIspreserveInsertionOrder=true;
        
        Object jObjRoot(bIspreserveInsertionOrder);//-------->use preserveInsertionOrder=true
        
        jObjRoot.set("id", 1123);
        jObjRoot.set("car",  ("这是中文abc@qwe.com1231,123.abc@hello.com,大圣归来..") );
        jObjRoot.set("total", 2);
    
        Poco::JSON::Array arrayResult;
        
        for(int nIndex=0;nIndex<2;nIndex++)
        {
            Object jArrayObj(bIspreserveInsertionOrder);
            jArrayObj.set("id", nIndex);
            jArrayObj.set("picture",("http://placehold.it/111.abc.") );
            jArrayObj.set("name",("这是中文测试.Crossman.") );
            jArrayObj.set("about",("《西游记之大圣归来》是根据中国传统神话故事进行拓展和演绎的3D动画电影.xxxx Consectetuer suscipit volutpat eros dolor .") );
    
            Poco::JSON::Array arrayFriends;
            for(int i=0;i<5;++i)
            {
                Object jarrayFriendsObj(bIspreserveInsertionOrder);
                jarrayFriendsObj.set("id", i);
                jarrayFriendsObj.set("name", (Poco::format("name%d,这是无可奈何花落去!",i)));
    
                arrayFriends.add(jarrayFriendsObj);
            }
    
    
            jArrayObj.set("friends",arrayFriends);
    
            arrayResult.add(jArrayObj);
    
        }
    
        jObjRoot.set("result",arrayResult);
        
        std::string strObjRoot;
        std::ostringstream ojObjRoot;
        //
        //bIspreserveInsertionOrder =false时程序正常运行.
        //bIspreserveInsertionOrder =true 时程序出错
        //PocoJSONObject.cpp 
        //const std::string& Object::getKey(KeyPtrList::const_iterator& iter) const
        //iter is null.
        //产生memcpy 错误..
        //
        jObjRoot.stringify(ojObjRoot);//
    
        strObjRoot=ojObjRoot.str();
        
        if(bUtf8)
            strObjRoot=CMyCodeConvert::Gb2312ToUtf8(strObjRoot);
        
        //std::string strGbkTemp=CMyCodeConvert::Utf8ToGb2312(strObjRoot);
        return strObjRoot;
    
    }

    原因是

    typedef std::deque<const std::string*> KeyPtrList; 这儿是指针地址,临时变量内容已经over了.

    so...再改改代码:

    pocoJSONincludePocoJSONObject.h 改动部分

    typedef std::deque< std::string> KeyPtrList;
    
    inline const Dynamic::Var& Object::getValue(KeyPtrList::const_iterator& it) const
    {
    const std::string & strKey=*it;
    ValueMap ::const_iterator iter = _values.find(strKey);
    if(iter!=_values.end())
    return iter->second;
    
    throw NotFoundException(strKey);
    }

    pocoJSONsrcObject.cpp 中改动部分:

    const std::string& Object::getKey(KeyPtrList::const_iterator& iter) const
    {
    ValueMap::const_iterator it = _values.begin();
    ValueMap::const_iterator end = _values.end();
    for (; it != end; ++it)
    {
    if (it->first == *iter) return it->first;
    }
    
    throw NotFoundException(*iter);
    }
    
    
    void Object::set(const std::string& key, const Dynamic::Var& value)
    {
    std::pair<ValueMap::iterator, bool> ret = _values.insert(ValueMap::value_type(key, value));
    if (_preserveInsOrder)
    {
    KeyPtrList::iterator it = _keys.begin();
    KeyPtrList::iterator end = _keys.end();
    for (; it != end; ++it)
    {
    if (key == *it) return;
    }
    _keys.push_back(ret.first->first);
    }
    }

       

      GetJsonSource()输出的结果可在 http://www.bejson.com/  中校验.

      -_- 终于成功了...

      

      把代码在debian下编译看下 通过http访问结果:

      

     

    然而作者又回复了我:

     Don't nest objects and arrays by value, it won't work properly - use smart pointers (Object::Ptr and Array::Ptr). See this issue for explanation.

     object.h,object.cpp还是用作者的code.

     

    poco开发版本地址:

    https://github.com/pocoproject/poco/blob/develop/JSON/include/Poco/JSON/Object.h

    https://github.com/pocoproject/poco/blob/develop/JSON/src/Object.cpp

    然后测试代码如下:

    std::string GetJsonSource(bool bUtf8)
    {
        bool bIspreserveInsertionOrder=true;
        
        //Object result(bIspreserveInsertionOrder);//-------->use preserveInsertionOrder=true
    
        //result.set("id", 1123);
    
        //Poco::JSON::Object::Ptr  inner= new Poco::JSON::Object(bIspreserveInsertionOrder) ;
        //inner->set("some_number", 5);
        //inner->set("some_string", "xyz");
        //std::string key = "new_object";
        //result.set(key, inner); // OK
        ////assert (result.isObject()); // OK
        //
    
        //std::string strOxxxxx;
        //std::ostringstream oxxxxx;
        //result.stringify(oxxxxx);//
        //strOxxxxx=oxxxxx.str();
    
        //return "";
    
    
        Object jObjRoot(bIspreserveInsertionOrder);//-------->use preserveInsertionOrder=true
        
        jObjRoot.set("id", 1123);
        jObjRoot.set("car",  ("这是中文abc@qwe.com1231,123.abc@hello.com,大圣归来..") );
        jObjRoot.set("total", 2);
    
        //Poco::JSON::Array arrayResult;
        Poco::JSON::Array::Ptr  parrayResult= new Poco::JSON::Array() ;
        for(int nIndex=0;nIndex<2;nIndex++)
        {
            Poco::JSON::Object::Ptr  pjArrayObj= new Poco::JSON::Object(bIspreserveInsertionOrder) ;
            //Object jArrayObj(bIspreserveInsertionOrder);
            pjArrayObj->set("id", nIndex);
            pjArrayObj->set("picture",("http://placehold.it/111.abc.") );
            pjArrayObj->set("name",("这是中文测试.Crossman.") );
            pjArrayObj->set("about",("《西游记之大圣归来》是根据中国传统神话故事进行拓展和演绎的3D动画电影.xxxx Consectetuer suscipit volutpat eros dolor .") );
    
            Poco::JSON::Array::Ptr  parrayFriends= new Poco::JSON::Array() ;
            //Poco::JSON::Array arrayFriends;
            for(int i=0;i<5;++i)
            {
                Poco::JSON::Object::Ptr  pjarrayFriendsObj= new Poco::JSON::Object(bIspreserveInsertionOrder) ;
                //Object jarrayFriendsObj(bIspreserveInsertionOrder);
                pjarrayFriendsObj->set("id", i);
                pjarrayFriendsObj->set("name", (Poco::format("name%d,这是无可奈何花落去!",i)));
    
                parrayFriends->add(pjarrayFriendsObj);
            }
    
    
            pjArrayObj->set("friends",parrayFriends);
    
            parrayResult->add(pjArrayObj);
    
        }
    
        jObjRoot.set("result",parrayResult);
        
        std::string strObjRoot;
        std::ostringstream ojObjRoot;
        ////
        jObjRoot.stringify(ojObjRoot);//
    
        strObjRoot=ojObjRoot.str();
        
        if(bUtf8)
            strObjRoot=CMyCodeConvert::Gb2312ToUtf8(strObjRoot);
        
        //std::string strGbkTemp=CMyCodeConvert::Utf8ToGb2312(strObjRoot);
        return strObjRoot;
    
    }

    这个问题终于得到解决...

  • 相关阅读:
    (转)我是一个小线程
    Gson本地和服务器环境不同遇到的Date转换问题 Failed to parse date []: Invalid time zone indicator
    Bigdecimal 比较equals与compareTo
    springboot jpa mongodb 多条件分页查询
    springboot Consider defining a bean of type 'xxx' in your configuration
    mongodb you can't add a second
    java8 获取某天最大(23:59:59)和最小时间(00:00:00)
    java volatile详解
    SpringBoot dubbo之class is not visible from class loader
    springboot dubbo filter之依赖注入null
  • 原文地址:https://www.cnblogs.com/bleachli/p/4668149.html
Copyright © 2011-2022 走看看