Reza
Reza

Reputation: 3919

How to use Boost XML Parser

I have written an XML parser for reading an XML file and convert it to an object of my "Position" class. It works fine. Please take a look at its code below.

XML File:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="15">
<position class_id="0" tracking_level="0" version="0">
    <Degrees>1</Degrees>
    <Minutes>2</Minutes>
    <Seconds>3</Seconds>
    <data class_id="1" tracking_level="0" version="0">
        <Degrees>1</Degrees>
        <Minutes>2</Minutes>
        <Seconds>3</Seconds>
    </data>
</position>
</boost_serialization>

Position Class:

#ifndef XMLMANAGER_POSITION_H
#define XMLMANAGER_POSITION_H

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

class Data
{
public:
    int Degrees;
    int Minutes;
    float Seconds;
private:
    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version){
        ar & BOOST_SERIALIZATION_NVP(Degrees);
        ar & BOOST_SERIALIZATION_NVP(Minutes);
        ar & BOOST_SERIALIZATION_NVP(Seconds);
    }
};
class Position
{

public:
    // every serializable class needs a constructor
    Position() {
        Degrees = 0;
        Minutes = 0;
        Seconds = 0;
    };
    Position(int degrees, int minutes, float seconds){
        Degrees = degrees;
        Minutes = minutes;
        Seconds = seconds;
    };
    int Degrees;
    int Minutes;
    float Seconds;
    Data data;

private:
    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version){
        ar & BOOST_SERIALIZATION_NVP(Degrees);
        ar & BOOST_SERIALIZATION_NVP(Minutes);
        ar & BOOST_SERIALIZATION_NVP(Seconds);
        ar & BOOST_SERIALIZATION_NVP(data);
    }
};

#endif //XMLMANAGER_POSITION_H

main Function:

    // Load an Object from XML
    std::ifstream ifs("/tests/r.karimi/XmlManager/data/Output.xml");
    boost::archive::xml_iarchive ixa(ifs);
    Position newPosition;
    try
    {
        ixa >> BOOST_SERIALIZATION_NVP(newPosition);
    }
    catch (std::exception const &ex)
    {
        std::cerr << ex.what() << std::endl;
    }
    std::cout << "Degree " << newPosition.Degrees <<
              " Minutes " << newPosition.Minutes <<
              " Seconds " << newPosition.Seconds << std::endl;
    std::cout << "Degree " << newPosition.data.Degrees <<
              " Minutes " << newPosition.data.Minutes <<
              " Seconds " << newPosition.data.Seconds << std::endl;

Now, I want to pasre the following XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="15">
<position class_id="0" tracking_level="0" version="0">
    <Degrees>0</Degrees>
    <Minutes>0</Minutes>
    <Seconds>0.000000000e+00</Seconds>
    <data class_id="1" tracking_level="0" version="0">
        <Degrees>1</Degrees>
        <Minutes>2</Minutes>
        <Seconds>3</Seconds>
    </data>
    <data class_id="1" tracking_level="0" version="0">
        <Degrees>4</Degrees>
        <Minutes>5</Minutes>
        <Seconds>6</Seconds>
    </data>
</position>
</boost_serialization>

What should I do? I have tried different solution such as get an array of "Data" class in "Position" class, but it does not work. I prefer to use Boost library for my project. (Unless it is not possible!!!)

Upvotes: 2

Views: 1897

Answers (1)

sehe
sehe

Reputation: 392931

Boost does not have an XML library.

Boost Serialization doesn't read general XML (like) documents. It reads XML archives only. Meaning, you don't control the XML.

That all said, you can simply extend the class with another Data member, and it would accidentally result in a very similar XML archive. Perhaps this is good enough for you:

Live On Coliru

#include <boost/archive/xml_oarchive.hpp>

class Data
{
public:
    int Degrees;
    int Minutes;
    float Seconds;
private:
    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int /*version*/){
        ar & BOOST_SERIALIZATION_NVP(Degrees);
        ar & BOOST_SERIALIZATION_NVP(Minutes);
        ar & BOOST_SERIALIZATION_NVP(Seconds);
    }
};

class Position
{

public:
    // every serializable class needs a constructor
    Position() {
        Degrees = 0;
        Minutes = 0;
        Seconds = 0;
    };
    Position(int degrees, int minutes, float seconds){
        Degrees = degrees;
        Minutes = minutes;
        Seconds = seconds;
    };
    int Degrees;
    int Minutes;
    float Seconds;
    Data data;
    Data data2;

private:
    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int /*version*/){
        ar & BOOST_SERIALIZATION_NVP(Degrees);
        ar & BOOST_SERIALIZATION_NVP(Minutes);
        ar & BOOST_SERIALIZATION_NVP(Seconds);
        ar & boost::serialization::make_nvp("data", data);
        ar & boost::serialization::make_nvp("data", data2);
    }
};

#include <fstream>

int main() {
    Position position;
    position.Degrees = 1;
    position.Minutes = 2;
    position.Seconds = 3;
    position.data = {1,2,3};
    position.data2 = {4,5,6};

    {
        std::ofstream ofs("output.xml");
        boost::archive::xml_oarchive oa(ofs);

        oa << BOOST_SERIALIZATION_NVP(position);
    }
}

Writes

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="14">
<position class_id="0" tracking_level="0" version="0">
    <Degrees>1</Degrees>
    <Minutes>2</Minutes>
    <Seconds>3.000000000e+00</Seconds>
    <data class_id="1" tracking_level="0" version="0">
        <Degrees>1</Degrees>
        <Minutes>2</Minutes>
        <Seconds>3.000000000e+00</Seconds>
    </data>
    <data>
        <Degrees>4</Degrees>
        <Minutes>5</Minutes>
        <Seconds>6.000000000e+00</Seconds>
    </data>
</position>
</boost_serialization>

UPDATE

If you DIDN'T want to control the XML, all the better. Just let the library do what you want it to do:

Live On Coliru

#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/serialization/vector.hpp>

class Data
{
public:
    int Degrees;
    int Minutes;
    float Seconds;
private:
    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int /*version*/){
        ar & BOOST_SERIALIZATION_NVP(Degrees);
        ar & BOOST_SERIALIZATION_NVP(Minutes);
        ar & BOOST_SERIALIZATION_NVP(Seconds);
    }
};

class Position
{

public:
    // every serializable class needs a constructor
    Position() {
        Degrees = 0;
        Minutes = 0;
        Seconds = 0;
    };
    Position(int degrees, int minutes, float seconds){
        Degrees = degrees;
        Minutes = minutes;
        Seconds = seconds;
    };
    int Degrees;
    int Minutes;
    float Seconds;
    std::vector<Data> data;

private:
    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int /*version*/){
        ar & BOOST_SERIALIZATION_NVP(Degrees);
        ar & BOOST_SERIALIZATION_NVP(Minutes);
        ar & BOOST_SERIALIZATION_NVP(Seconds);
        ar & boost::serialization::make_nvp("data", data);
    }
};

#include <fstream>

int main() {
    {
        Position position;
        position.Degrees = 1;
        position.Minutes = 2;
        position.Seconds = 3;
        position.data = { {1,2,3}, {4,5,6 } };

        std::ofstream ofs("output.xml");
        boost::archive::xml_oarchive oa(ofs);

        oa << BOOST_SERIALIZATION_NVP(position);
    }
    {
        std::ifstream ifs("output.xml");
        boost::archive::xml_iarchive ia(ifs);

        Position position;
        ia >> BOOST_SERIALIZATION_NVP(position);
    }
}

In this case, the XML happens to look like:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="14">
<position class_id="0" tracking_level="0" version="0">
    <Degrees>1</Degrees>
    <Minutes>2</Minutes>
    <Seconds>3.000000000e+00</Seconds>
    <data class_id="1" tracking_level="0" version="0">
        <count>2</count>
        <item_version>0</item_version>
        <item class_id="2" tracking_level="0" version="0">
            <Degrees>1</Degrees>
            <Minutes>2</Minutes>
            <Seconds>3.000000000e+00</Seconds>
        </item>
        <item>
            <Degrees>4</Degrees>
            <Minutes>5</Minutes>
            <Seconds>6.000000000e+00</Seconds>
        </item>
    </data>
</position>
</boost_serialization>

Upvotes: 2

Related Questions