在使用poco version 1.6.0時 Poco::JSON::Array 在object 設置preserveInsertionOrder =true 時
調用 array.stringify出錯.
在使用poco::json 輸出字符串
std::string str1 = "\r"; std::string str2 = "\n"; 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", "這是中文[email protected]"); 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
追蹤代碼發現:
\JSON\src\Object.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);
----->
JSON\src\Stringifier.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);
}
--->
\JSON\src\Object.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
}
--->
\Poco\JSON\Object.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);
...
}
\JSON\src\Object.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)時
Foundation\include\Poco\Dynamic\Var.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", "這是中文[email protected]"); 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":"這是中文[email protected]","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\": \" [email protected],大聖歸來.. \"," //"\"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", ("這是中文[email protected],[email protected],大聖歸來..") ); 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 時程序出錯 //Poco\JSON\Object.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...再改改代碼:
poco\JSON\include\Poco\JSON\Object.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); }
poco\JSON\src\Object.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訪問結果: