我正在使用boost图库。我需要序列化图形对象,稍后将其读出。但我发现了程序无法使用XML存档程序正常工作。它总是抛出异常说:
XML开始/结束标记不匹配-位置。
我没有定义名为我的序列化代码中的"position"
。我不知道怎么做来解决它。这是一个演示问题。
types.h
#ifndef TYPES_H
#define TYPES_H
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/adj_list_serialize.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/deque.hpp>
#include <boost/serialization/variant.hpp>
#include <boost/variant.hpp>
#include <boost/ref.hpp>
using namespace boost;
namespace bmi = boost::multi_index;
class QTable; //forward declaration
typedef QTable Eligibility;
//观测类型
enum Observation{present,absent,idle};
//1)图模型的定义
enum vertex_BatteryLevel_t {vertex_BatteryLevel};
enum vertex_ObservationHistory_t {vertex_ObservationHistory};
enum edge_QFunction_t {edge_QFunction};
enum edge_Eligibility_t {edge_Eligibility};
namespace boost {
BOOST_INSTALL_PROPERTY(vertex,BatteryLevel);
BOOST_INSTALL_PROPERTY(vertex,ObservationHistory);
BOOST_INSTALL_PROPERTY(edge,QFunction);
BOOST_INSTALL_PROPERTY(edge,Eligibility);
}
typedef property<vertex_BatteryLevel_t,int,
property<vertex_ObservationHistory_t,std::deque<Observation>,
property<vertex_index_t,int>
>
> vertex_state;
typedef property<edge_QFunction_t,QTable,
property<edge_Eligibility_t,Eligibility>
> edge_qfunction;
typedef adjacency_list<
vecS,setS,directedS, //结点用vecSå› ä¸ºæ— éœ€åŠ¨æ€æ”¹å˜ç»“点个数,用setS表示边为了强调是简å•å›¾ï¼ˆä¸¤ä¸ªç»“点之间一个方å‘çš„è¾¹åªèƒ½æœ‰ä¸€æ¡ï¼‰
vertex_state, //节点的电é‡å’Œè§‚测历å²
edge_qfunction //æ¯ä¸ªæœ‰å‘边对应一个ublas::matrix<double>对象属性
> Graph;
//2)Q函数的定义
//行为类型
enum NotSensing{off=-2,recharge=-1};
typedef variant<int,NotSensing> Action; //action={å„个方å‘,off,recharge}
//state=<历å²è§‚测,ç”µæ± ç”µé‡>
struct Status {
friend class boost::serialization::access;
template<class Archive> void serialize(Archive & ar,const unsigned int version);
//从结点id->观测历å²çš„æ˜ å°„
//æ¯ä¸€ä¸ªæ—¶åˆ»çš„历å²è§‚测顺åºæ˜¯ä¼ 感器本身,按照è¿ä»£å™¨é¡ºåºçš„å…¶ä»–ä¼ æ„Ÿå™¨è§‚æµ‹
typedef std::map<int,std::deque<Observation> > HistoryType;
HistoryType history;
int batteryLevel; //ç”µæ± ç”µé‡
Status() {}
Status(const HistoryType & h,const int & bl);
Status(const Status & s);
~Status() {}
friend bool operator<(const Status & idx1,const Status & idx2);
friend bool operator==(const Status & idx1,const Status & idx2);
};
template<class Archive>
inline void Status::serialize(Archive & ar,const unsigned int)
{
ar & boost::serialization::make_nvp("history",history);
ar & boost::serialization::make_nvp("batteryLevel",batteryLevel);
}
struct QTableElem {
friend class boost::serialization::access;
template<class Archive> void serialize(Archive &,const unsigned int) {}
Status status;
Action myaction, youraction;
double value;
QTableElem(const Status & s,const Action & ma,const Action & ya,double v)
: status(s),myaction(ma),youraction(ya),value(v) {}
};
typedef QTableElem EligibilityElem;
//å› ä¸ºtypedefä¸èƒ½circular dependent所以需è¦å®šä¹‰ä¸ªç±»ç»§æ‰¿å…¶ä¸ä¸€ä¸ªtypedef。
class QTable : public bmi::multi_index_container <
QTableElem,
bmi::indexed_by <
bmi::ordered_unique<
bmi::composite_key<
QTableElem,
bmi::member<QTableElem,Status,&QTableElem::status>,
bmi::member<QTableElem,Action,&QTableElem::myaction>,
bmi::member<QTableElem,Action,&QTableElem::youraction>
>
>,
bmi::ordered_non_unique<bmi::member<QTableElem,Status,&QTableElem::status> >
>
> {};
namespace boost {
namespace serialization {
template<class Archive> inline void save_construct_data(Archive & ar,const QTableElem * e,const unsigned int) {
ar << boost::serialization::make_nvp("status",e->status);
ar << boost::serialization::make_nvp("myaction",e->myaction);
ar << boost::serialization::make_nvp("youraction",e->youraction);
ar << boost::serialization::make_nvp("value",e->value);
}
template<class Archive> void load_construct_data(Archive & ar,QTableElem * e,const unsigned int) {
Status s;
Action ma,ya;
double v;
ar >> boost::serialization::make_nvp("status",s);
ar >> boost::serialization::make_nvp("myaction",ma);
ar >> boost::serialization::make_nvp("youraction",ya);
ar >> boost::serialization::make_nvp("value",v);
::new(e) QTableElem(s,ma,ya,v);
}
}
}
#endif
types.cpp
#include <stdexcept>
#include "types.h"
Status::Status(const Status::HistoryType & h,const int & bl)
:history(h),batteryLevel(bl)
{
}
Status::Status(const Status & s)
:history(s.history),batteryLevel(s.batteryLevel)
{
}
bool operator<(const Status & idx1,const Status & idx2)
{
#ifndef NDEBUG
assert(idx1.history.size() == idx2.history.size());
#endif
Status::HistoryType::const_iterator it,it2;
for(it = idx1.history.begin(), it2 = idx2.history.begin() ; it != idx1.history.end() && it2 != idx2.history.end() ; it++,it2++) {
#ifndef NDEBUG
assert(it->first == it2->first);
assert(it->second.size() == it2->second.size());
#endif
std::deque<Observation>::const_iterator itt,itt2;
for(itt = it->second.begin(), itt2 = it2->second.begin() ; itt != it->second.end() && itt2 != it2->second.end() ; itt++,itt2++) {
if(*itt < *itt2) return true;
if(*itt > *itt2) return false;
}
}
#ifndef NDEBUG
assert(it == idx1.history.end() && it2 == idx2.history.end());
#endif
return false;
}
bool operator==(const Status & idx1,const Status & idx2)
{
#ifndef NDEBUG
assert(idx1.history.size() == idx2.history.size());
#endif
Status::HistoryType::const_iterator it, it2;
for(it = idx1.history.begin(), it2 = idx2.history.begin() ; it != idx1.history.end() && it2 != idx2.history.end() ; it++,it2++) {
#ifndef NDEBUG
assert(it->first == it2->first);
assert(it->second.size() == it2->second.size());
#endif
std::deque<Observation>::const_iterator itt,itt2;
for(itt = it->second.begin(), itt2 = it2->second.begin() ; itt != it->second.end() && itt2 != it2->second.end() ; itt++,itt2++) {
if(*itt != *itt2) return false;
}
}
#ifndef NDEBUG
assert(it == idx1.history.end() && it2 == idx2.history.end());
#endif
return true;
}
main.cpp
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include "types.h"
//compile with "g++ main.cpp types.cpp -I. -o test -lboost_serialization"
int main()
{
using boost::serialization::make_nvp;
{
//load vertices
std::ifstream in("../graph.txt");
if (false == in.is_open())
throw std::runtime_error("invalid graph model file!");
typedef graph_traits<Graph>::vertices_size_type size_type;
size_type n_vertices;
in >> n_vertices;
std::istream_iterator<std::pair<size_type, size_type> > input_begin(in), input_end;
Graph g(input_begin, input_end, n_vertices);
//serialize the graph object
{
std::ofstream out("../test.xml");
if (false == out.is_open()) throw std::runtime_error("invalid file!");
boost::archive::xml_oarchive oa(out);
oa << make_nvp("graph", g);
}
}
{
//deserialize from the file
std::ifstream xml("../test.xml");
if (false == xml.is_open())
throw std::runtime_error("invalid file!");
{
boost::archive::xml_iarchive ia(xml);
Graph g;
try {
ia >> make_nvp("graph", g);
}
catch (boost::archive::archive_exception const& ae)
{
std::cout << "Error: " << ae.code << ":'" << ae.what() << "'n";
}
}
}
}
namespace std {
template <typename T> istream & operator>>(istream & in,pair<T,T>& p) {
in >> p.first >> p.second;
return in;
}
}
一如既往的
- 从小处着手,逐步构建,并在每一步测试
发生意外故障时:
- 消除原因(分而治之(
如果你这样做了,你会很快发现即使是
Eligibility e;
oa << make_nvp("e", e);
然后是
ia >> make_nvp("e", e);
将显示完全相同的问题,甚至没有任何数据。问题是QTable
从boost::multi_index_container
派生,这破坏了它的序列化实现
这是Coliru上的最小复制器
namespace bmi = boost::multi_index;
struct QTableElem {
template<class Archive> void serialize(Archive &ar,const unsigned int) {
ar & boost::serialization::make_nvp("dummy", dummy);
}
int dummy;
};
class QTable : public bmi::multi_index_container<
QTableElem,
bmi::indexed_by<
bmi::ordered_unique<bmi::member<QTableElem,int,&QTableElem::dummy> >
>
> {};
int main()
{
using boost::serialization::make_nvp;
{
std::ofstream out("test.xml");
boost::archive::xml_oarchive oa(out);
QTable obj;
oa << make_nvp("graph", obj);
}
try {
std::ifstream xml("test.xml");
boost::archive::xml_iarchive ia(xml);
QTable obj;
ia >> make_nvp("graph", obj);
} catch (boost::archive::archive_exception const& ae) {
std::cout << "Error: " << ae.code << ":'" << ae.what() << "'n";
}
}
打印
g++ -std=c++03 -O2 -Wall -pedantic -pthread main.cpp -lboost_system -lboost_serialization && ./a.out
Error: 1:'position'
注意:错误实际上不是与关闭元素有关(W3C的良好格式检查也会告诉你这一点(
现在,要修复SSCCE,只需删除继承:
在Coliru上直播
typedef bmi::multi_index_container<
QTableElem,
bmi::indexed_by<
bmi::ordered_unique<bmi::member<QTableElem,int,&QTableElem::dummy> >
>
> QTable;
我对你的图形样本也做了同样的处理。它起了作用(就测试而言(:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="12">
<graph class_id="0" tracking_level="0" version="0">
<V>20</V>
<E>60</E>
<vertex_property class_id="1" tracking_level="0" version="0">
<property_value>0</property_value>
<property_base class_id="2" tracking_level="0" version="0">
<property_value class_id="3" tracking_level="0" version="0">
<count>0</count>
<item_version>0</item_version>
</property_value>
<property_base class_id="4" tracking_level="0" version="0">
<property_value>0</property_value>
<property_base class_id="5" tracking_level="0" version="0"></property_base>
</property_base>
</property_base>
</vertex_property>
<vertex_property>
<property_value>0</property_value>
<property_base>
<property_value>
<count>0</count>
<item_version>0</item_version>
</property_value>
<property_base>
<property_value>0</property_value>
<property_base></property_base>
</property_base>
</property_base>
</vertex_property>
<vertex_property>
<property_value>0</property_value>
<property_base>
<property_value>
<count>0</count>
<item_version>0</item_version>
</property_value>
<property_base>
<property_value>0</property_value>
<property_base></property_base>
</property_base>
</property_base>
</vertex_property>
<vertex_property>
<property_value>0</property_value>
<property_base>
<property_value>
<count>0</count>
<item_version>0</item_version>
</property_value>
<property_base>
<property_value>0</property_value>
<property_base></property_base>
</property_base>
</property_base>
</vertex_property>
<vertex_property>
<property_value>0</property_value>
<property_base>
<property_value>
<count>0</count>
<item_version>0</item_version>
</property_value>
<property_base>
<property_value>0</property_value>
<property_base></property_base>
</property_base>
</property_base>
</vertex_property>
....
<v>15</v>
<edge_property>
<property_value>
<count>0</count>
<value_version></value_version>
<position object_id="_56"></position>
<pointer class_id="-1"></pointer>
</property_value>
<property_base></property_base>
</edge_property>
<u>19</u>
<v>5</v>
<edge_property>
<property_value>
<count>0</count>
<value_version></value_version>
<position object_id="_57"></position>
<pointer class_id="-1"></pointer>
</property_value>
<property_base></property_base>
</edge_property>
<u>19</u>
<v>17</v>
<edge_property>
<property_value>
<count>0</count>
<value_version></value_version>
<position object_id="_58"></position>
<pointer class_id="-1"></pointer>
</property_value>
<property_base></property_base>
</edge_property>
<u>19</u>
<v>13</v>
<edge_property>
<property_value>
<count>0</count>
<value_version></value_version>
<position object_id="_59"></position>
<pointer class_id="-1"></pointer>
</property_value>
<property_base></property_base>
</edge_property>
<graph_property></graph_property>
</graph>
</boost_serialization>
如果您想查看它,请参阅:https://gist.github.com/sehe/093f823937486eb99d2f