boost serialization exception, to and from xml, via sql server xml datatype

952 Views Asked by At

Ok, here's my problem.

I have a boost object which creates xml string via serialization, this works just fine.

Using boost version 1.38

I take that xml string and save it to a sql server database table into an xml datatype, this also work fine.

I then retrieve my xml string from the database table, but the format has changed slightly from when it was inserted, basically blank values have been short tagged, from <data></data> to <data/>

Here's an example of the xml before and after.

Before

<grid class_id="0" tracking_level="0" version="0">
    <name>test_table</name>
    <columns class_id="1" tracking_level="0" version="0">
        <count>2</count>
        <item_version>0</item_version>
        <item class_id="2" tracking_level="1" version="0" object_id="_0">
            <label>AAAA</label>
            <data>xxxx</data>
        </item>
        <item class_id_reference="2" object_id="_1">
      <label>BBBB</label>
      <data></data>
    </item>
    </columns>
</grid>

After

<grid class_id="0" tracking_level="0" version="0">
  <name>test_table</name>
  <columns class_id="1" tracking_level="0" version="0">
    <count>2</count>
    <item_version>0</item_version>
    <item class_id="2" tracking_level="1" version="0" object_id="_0">
      <label>AAAA</label>
      <data>xxxx</data>
    </item>
    <item class_id_reference="2" object_id="_1">
      <label>BBBB</label>
      <data /> <!-- NOW SHORT TAGGED -->
    </item>
  </columns>
</grid>

This is also fine and perfectly acceptable and not unexpected.

The problem comes when I take this xml string and try to serialize the xml back into the boost objects, it throws and exception when it comes across the short tagged tag in the xml string.

I've hit a brick wall with this and don't know how to fix the problem, and can't find any reference to this problem on the web, so any help would be greatly appreciated.

:)

Here's my code, it should compile without any issues, you just need to fill in the blanks for the db part:

grid.hpp

////////////////////////////////////////////////////////////////
// grid boost serialization object
//
#pragma once

#include <string>
#include <iomanip>
#include <iostream>
#include <fstream>

#include <boost/serialization/nvp.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/version.hpp>

/////////////////////////////////////////////////////////////
// Column
//
namespace sdcm
{

class Column
{
public:
    // every serializable class needs a constructor
    Column()
    {
    }

    Column(const std::string& _label, const std::string& _data)
    :   label(_label),
        data(_data)
    {
    }

private:
    friend class boost::serialization::access;
    friend std::ostream & operator<<(std::ostream &os, const Column &col);

    std::string label;
    std::string data;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int /* file_version */)
    {
        ar  & BOOST_SERIALIZATION_NVP(label)
            & BOOST_SERIALIZATION_NVP(data)
            ;
    }
};

class Grid
{
public:
    // every serializable class needs a constructor
    Grid()
    {
    }

    Grid(const std::string& _name)
    :   name(_name)
    {
    }

    void append(Column* col)
    {
        columns.insert(columns.end(), col);
    }

private:
    friend class boost::serialization::access;
    friend std::ostream & operator<<(std::ostream &os, const Grid &grid);

    std::string name;

    typedef Column* GRID_COLUMNS;
    std::list<GRID_COLUMNS> columns;

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
        ar  & BOOST_SERIALIZATION_NVP(name)
            & BOOST_SERIALIZATION_NVP(columns);
    }
};

} // end namespace

main.cpp

// boost_test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <sstream>
#include <iostream>
#include <string>

#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include "grid.hpp"

std::string get_grid_as_xml_str(sdcm::Grid& grid)
{
    std::ostringstream xml ;
    unsigned int flags = boost::archive::no_header
                        //| boost::archive::no_codecvt
                        //| boost::archive::no_xml_tag_checking
                        //| boost::archive::no_tracking
                        ;

    boost::archive::xml_oarchive oa(xml, flags);
    oa << BOOST_SERIALIZATION_NVP(grid);
    return xml.str();
}

void restore_grid_from_xml_str(sdcm::Grid& grid, const std::string& xml_str)
{
    std::istringstream xml(xml_str);
    unsigned int flags = boost::archive::no_header
                        //| boost::archive::no_codecvt
                        //| boost::archive::no_xml_tag_checking
                        //| boost::archive::no_tracking
                        ;

    boost::archive::xml_iarchive ia(xml, flags);
    ia >> BOOST_SERIALIZATION_NVP(grid);
}

int _tmain(int argc, _TCHAR* argv[])
{   
    // create grid obj with cols
    sdcm::Grid grid("MY GRID");
    grid.append(new sdcm::Column("AAAA", "xxxx")) ;
    grid.append(new sdcm::Column("BBBB", "")) ;

    // get grid as xml string
    std::string xml = get_grid_as_xml_str(grid) ;

    // Assume xml is saved to SQL Server DB table in XML datatype,
    // and the data has be retrived is a shorted tag format used
    // where blank values are present in tags

    // make a new grid
    sdcm::Grid new_grid;
    restore_grid_from_xml_str(new_grid, xml);

    return 0;
}
1

There are 1 best solutions below

0
On BEST ANSWER

Bit late, but I did get a reply email from boost.

Yes it is somewhat of a bug, but they are not going to fix it.

Here the reply if our interested:

The xml_archive code, as does all the serialization code presumes that we load exactly what we save. Generally trying to make it more general never seemed worth the risk. If you want to create, test and submit a patch to the spirit parser which would handle the tags I would look at it. But lacking this, I'm not inclined to spend time on this.