Да, ваш ответ был действительно потрясающим. Но другой также учит нас, как лучше сериализовать объекты списка. Спасибо за ответ, сэр.

аюсь сериализовать свои классы в XML. Мои занятия;

class HardwareDto{
    friend class boost::serialization::access;
    template<class Archive> void serialize(Archive & ar, const unsigned int version) {
        ar & BOOST_SERIALIZATION_NVP(HardwareID);
        ar & BOOST_SERIALIZATION_NVP(HardwareHostID);
        ar & BOOST_SERIALIZATION_NVP(HardwareFriendlyName);
    }
public:
    int HardwareID;
    int HardwareHostID;
    string HardwareFriendlyName;
    inline HardwareDto(int HardwareHostID, int HardwareID, string HardwareFriendlyName) {
        this->HardwareHostID = HardwareHostID;
        this->HardwareID = HardwareID;
        this->HardwareFriendlyName = HardwareFriendlyName;
    }
};

И класс, который содержитHardwareDto список.

class HardwareHostDto {
private:
    friend class boost::serialization::access;
    template<class Archive> void serialize(Archive & ar, const unsigned int version) {
        ar & BOOST_SERIALIZATION_NVP(HardwareHostID);
        ar & BOOST_SERIALIZATION_NVP(BranchID);
        ar & BOOST_SERIALIZATION_NVP(HardwareHostFriendlyName);
        ar & BOOST_SERIALIZATION_NVP(HardwareList);
    }

public:
    int HardwareHostID;
    int BranchID;
    string HardwareHostFriendlyName ;
    HardwareDto* HardwareList[20];

    inline HardwareHostDto(int HardwareHostID, int BranchID, string HardwareHostFriendlyName, HardwareDto* HardwareList[20]) {
        this->HardwareHostID = HardwareHostID;
        this->BranchID = BranchID;
        this->HardwareHostFriendlyName = HardwareHostFriendlyName;
        this->HardwareList[0] = HardwareList[0];
    }
};

А также

HardwareDto *HardwareList[20]; 

мой глобальный список hardwaredto В этом примере я только вставил один объект hardwarehostdto в этот список.

Я пытаюсь сериализовать это через функцию повышения:

std::ofstream ofs("filename.xml");

unsigned int flags = boost::archive::no_header;
boost::archive::xml_iarchive ia(is, boost::archive::no_header);
boost::archive::xml_oarchive oa(ofs, flags);

HardwareHostDto* HardwareHost = new HardwareHostDto(1, 1, "kiosk", HardwareList);

oa << BOOST_SERIALIZATION_NVP(HardwareHost);

После выполнения этого кода я получил следующее filename.xml:

<HardwareHost class_id="0">
    <HardwareHostID>1</HardwareHostID>
    <BranchID>1</BranchID>
    <HardwareHostFriendlyName>kiosk</HardwareHostFriendlyName>
    <HardwareList>
        <count>20</count>
        <item class_id="1">
            <HardwareID>2</HardwareID>
            <HardwareHostID>2</HardwareHostID>
            <HardwareFriendlyName>Ankara</HardwareFriendlyName>
        </item>
    </HardwareList>
</HardwareHost>

<item> тег должен быть<Hardware> но я не могу изменить это. Мой вопрос: есть ли способ изменить<item> тег, или Actullay настроить эту структуру XML, как нет<count> тег или флаги? Я нашел несколько способов сделать это на веб-сайте Boost, но не смог с этим справиться.

Спасибо.

 sehe03 дек. 2017 г., 23:26
Вопрос о повышении. Ваш код и все ответы содержат Boost Serialization. Лучше всего сохранить тег.
 sehe23 нояб. 2017 г., 15:39
Почему вы храните указатели и динамически распределяете? Ваш код будет утечка памяти сейчас.

Ответы на вопрос(2)

вы можете написать свой собственный архив XML. Это трехступенчатый процесс:

Определите класс, который пишет примитивные типы, скажем,TextOPrimitiveOnXML.Определите класс, который пишет составные типы:BasicXMLOArchive, Это класс, который будет писать теги XML.Склеить все вместе вXMLOArchive.

Преимущество в том, что не только вы можете повторно использовать свойserialize код, но также вы можете использовать разные бэкэнды. Например, у вас может быть архив, который сразу же создает DOM, а не просто вывод текста.

Вот скелеты для классов, которые я упомянул.

TextOPrimitiveOnXML, егоsave методы определяют написание примитивных типов.

class TextOPrimitiveOnXML
{
protected:
  TextOPrimitiveOnXML()
  {}
  template <class T>
  void save(const T & t) {
  }
  void save(const bool t) {
  }
  void save(const signed char t) {
  }
  void save(const unsigned char t) {
  }
  void save(const char t) {
  }
  void save(const wchar_t t) {
  }
  void save(const char *t) {
  }
  void save(const wchar_t *t) {
  }
  void save(const std::string &t) {
  }
  void save(const std::wstring &t) {
  }
  void save_binary(const void *address, std::size_t count);
};

BasicXMLOArchiveЗдесь вы можете манипулировать тегами и атрибутами:

template <class Archive>
class BasicXMLOArchive :
  public boost::archive::detail::common_oarchive<Archive>
{
  friend class boost::archive::detail::interface_oarchive<Archive>;
  friend class boost::archive::save_access;

  typedef boost::archive::detail::common_oarchive<Archive> base;

protected:
  void init() {
  }

  BasicXMLOArchive(unsigned int flags)
    : base(flags)
  {}

  template <class T>
  void save_override(T & t, int)
  {
    // If your program fails to compile here, its most likely due to
    // not specifying an nvp wrapper around the variable to
    // be serialized.
    BOOST_MPL_ASSERT((boost::serialization::is_wrapper<T>));
    this->base::save_override(t, 0);
  }

  // special treatment for name-value pairs.
  template <class T>
  void save_override(const boost::serialization::nvp<T> &t, int)
  {
  }

  void save_override(co,nst boost::archive::object_id_type & t);
  void save_override(const boost::archive::object_reference_type & t);
  void save_override(const boost::archive::version_type & t);
  void save_override(const boost::archive::class_id_type & t);
  void save_override(const boost::archive::class_id_optional_type & t);
  void save_override(const boost::archive::class_id_reference_type & t);
  void save_override(const boost::archive::class_name_type & t);
  void save_override(const boost::archive::tracking_type & t);

public:
  boost::archive::library_version_type get_library_version() const {
    return boost::archive::library_version_type(0);
  }
};

Конечный клей:

template <class Archive>
class XMLOArchiveImpl :
    public TextOPrimitiveOnXML
  , public BasicXMLOArchive<Archive>
{
  friend class boost::archive::save_access;
public:
  XMLOArchiveImpl(unsigned int flags)
    : TextOPrimitiveOnXML()
    , BasicXMLOArchive<Archive>(flags)
  {
    init();
  }

  void save_binary(const void *address, std::size_t count){
    this->TextOPrimitiveOnXML::save_binary(address, count);
  }
};

class XMLOArchive :
  public XMLOArchiveImpl<XMLOArchive>
{
  friend class BasicXMLOArchive<XMLOArchive>;
public:
  XMLOArchive(unsigned int flags)
    : XMLOArchiveImpl(flags)
  {}
};
 facetus25 нояб. 2017 г., 21:53
Нет проблем. Я бы на самом деле объединил оба ответа и написал бы улучшенный архив, который использует PugiXML в качестве бэкэнда. Мне нравится Boost :).
 Marijke Buurlage24 нояб. 2017 г., 10:18
Спасибо за ваш ответ, но верхний ответ лучше для меня.
 Marijke Buurlage25 нояб. 2017 г., 21:57
Да, ваш ответ был действительно потрясающим. Но другой также учит нас, как лучше сериализовать объекты списка. Спасибо за ответ, сэр.
Решение Вопроса

как настроить именование по умолчанию для Boost xml Serialization по умолчанию, чтобы сделать его более читаемымКак использовать Boost XML Parserпроблема десериализации после изменения пространства имен для настройки имен тегов для boost xml

И нет, ты не должен. Используйте библиотеку XML для написания произвольного XML.

Boost Serialization только делает сериализацию. Формат архива - это деталь реализации.

Плохой пример

какаяне делать (это нарушает не-стандартные типы, которые могут быть разрушены, это нарушает управление версиями).

С другой стороны, этот код не пропускает память.

Жить на Колиру

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

class HardwareDto {
    friend class boost::serialization::access;
    template <class Archive> void serialize(Archive &ar, unsigned) {
        ar &BOOST_SERIALIZATION_NVP(HardwareID);
        ar &BOOST_SERIALIZATION_NVP(HardwareHostID);
        ar &BOOST_SERIALIZATION_NVP(HardwareFriendlyName);
    }

  public:
    int HardwareHostID;
    int HardwareID;
    std::string HardwareFriendlyName;

    HardwareDto(int HardwareHostID = -1, int HardwareID = -1, std::string HardwareFriendlyName = {})
       : HardwareHostID(HardwareHostID),
         HardwareID(HardwareID),
         HardwareFriendlyName(HardwareFriendlyName)
    { }
};

using HardwareDtoList = std::vector<HardwareDto>;

class HardwareHostDto {
  private:
    friend class boost::serialization::access;
    template <class Archive> void serialize(Archive &ar, unsigned) {
        ar &BOOST_SERIALIZATION_NVP(HardwareHostID);
        ar &BOOST_SERIALIZATION_NVP(BranchID);
        ar &BOOST_SERIALIZATION_NVP(HardwareHostFriendlyName);
        ar &BOOST_SERIALIZATION_NVP(HardwareList);
    }

  public:
    int HardwareHostID;
    int BranchID;
    std::string HardwareHostFriendlyName;
    HardwareDtoList HardwareList;

    HardwareHostDto(int HardwareHostID, int BranchID, std::string HardwareHostFriendlyName, HardwareDtoList HardwareList) 
        : HardwareHostID(HardwareHostID),
          BranchID(BranchID),
          HardwareHostFriendlyName(HardwareHostFriendlyName),
          HardwareList(HardwareList)
    { }
};

namespace boost { namespace serialization {
    template <typename Ar>
        void serialize(Ar& ar, std::vector<HardwareDto>& v, unsigned) {
            size_t count = v.size();
            ar & BOOST_SERIALIZATION_NVP(count);
            v.resize(count);

            for (auto& el : v)
                ar & boost::serialization::make_nvp("Hardware", el);
        }
} }

#include <fstream>
#include <iostream>

int main() {
    unsigned int flags = boost::archive::no_header;

    {
        HardwareDtoList HardwareList;
        HardwareList.emplace_back(1, 2, "friendly");

        std::ofstream ofs("filename.xml");
        boost::archive::xml_oarchive oa(ofs, flags);

        HardwareHostDto host(1, 1, "kiosk", HardwareList);

        oa << boost::serialization::make_nvp("HardwareHost", host);
    }

    {
        HardwareHostDto roundtrip(-1, -1, "", {});
        std::ifstream ifs("filename.xml");
        boost::archive::xml_iarchive ia(ifs, flags);

        ia >> boost::serialization::make_nvp("HardwareHost", roundtrip);

        std::cout << "Read back: " << roundtrip.HardwareHostID << "\n";
        std::cout << "Read back: " << roundtrip.BranchID << "\n";
        std::cout << "Read back: " << roundtrip.HardwareHostFriendlyName << "\n";
        for (auto& h: roundtrip.HardwareList) {
            std::cout << "Item: " << h.HardwareID << ", " << h.HardwareHostID << ", " << h.HardwareFriendlyName << "\n";
        }
    }

}

Печать

Read back: 1
Read back: 1
Read back: kiosk
Item: 2, 1, friendly

И пишет XML как:

<HardwareHost class_id="0" tracking_level="0" version="0">
    <HardwareHostID>1</HardwareHostID>
    <BranchID>1</BranchID>
    <HardwareHostFriendlyName>kiosk</HardwareHostFriendlyName>
    <HardwareList class_id="1" tracking_level="0" version="0">
        <count>1</count>
        <Hardware class_id="2" tracking_level="0" version="0">
            <HardwareID>2</HardwareID>
            <HardwareHostID>1</HardwareHostID>
            <HardwareFriendlyName>friendly</HardwareFriendlyName>
        </Hardware>
    </HardwareList>
</HardwareHost>
Что делать

Использование библиотеки XML. Это требует (большого) обобщения, но вот начало использования PugiXML:

Жить На колиру

#include <pugixml.hpp>
#include <iostream>
#include <vector>

struct HardwareDto {
    int HardwareHostID;
    int HardwareID;
    std::string HardwareFriendlyName;
};

struct HardwareHostDto {
    int HardwareHostID;
    int BranchID;
    std::string HardwareHostFriendlyName;
    std::vector<HardwareDto> HardwareList;
};

struct Xml {
    struct Saver {
        template <typename T>
        void operator()(pugi::xml_node parent, std::string const& name, T const& value) const {
            auto node = named_child(parent, name);
            node.text().set(to_xml(value));
        }

        void operator()(pugi::xml_node parent, std::string const& name, HardwareDto const& o) const {
            auto dto = named_child(parent, name);
            operator()(dto, "HardwareHostID", o.HardwareHostID);
            operator()(dto, "HardwareID", o.HardwareID);
            operator()(dto, "HardwareFriendlyName", o.HardwareFriendlyName);
        }

        template <typename C>
        void operator()(pugi::xml_node parent, std::string const& name, std::string const& item_name, C const& container) const {
            auto list = named_child(parent, name);

            for (auto& item : container)
                operator()(list, item_name, item);
        }

        void operator()(pugi::xml_node parent, std::string const& name, HardwareHostDto const& o) const {
            auto dto = named_child(parent, name);
            operator()(dto, "HardwareHostID", o.HardwareHostID);
            operator()(dto, "BranchID", o.BranchID);
            operator()(dto, "HardwareHostFriendlyName", o.HardwareHostFriendlyName);
            operator()(dto, "HardwareList", "Hardware", o.HardwareList);
        }
      private:
        // serialization
        template <typename T> static T const& to_xml(T const& v) { return v; }
        static char const* to_xml(std::string const& v) { return v.c_str(); }

        pugi::xml_node named_child(pugi::xml_node parent, std::string const& name) const {
            auto child = parent.append_child();
            child.set_name(name.c_str());
            return child;
        }
    };

    struct Loader {
        void operator()(pugi::xml_node parent, std::string const& name, std::string& value) const {
            auto node = parent.first_element_by_path(name.c_str());
            value = node.text().as_string();
        }
        void operator()(pugi::xml_node parent, std::string const& name, int& value) const {
            auto node = parent.first_element_by_path(name.c_str());
            value = node.text().as_int();
        }

        void operator()(pugi::xml_node dto, HardwareDto& o) const {
            operator()(dto, "HardwareHostID", o.HardwareHostID);
            operator()(dto, "HardwareID", o.HardwareID);
            operator()(dto, "HardwareFriendlyName", o.HardwareFriendlyName);
        }

        void operator()(pugi::xml_node parent, std::string const& name, HardwareDto& o) const {
            auto dto = parent.first_element_by_path(name.c_str());
            operator()(dto, "HardwareHostID", o.HardwareHostID);
            operator()(dto, "HardwareID", o.HardwareID);
            operator()(dto, "HardwareFriendlyName", o.HardwareFriendlyName);
        }

        template <typename C>
        void operator()(pugi::xml_node parent, std::string const& name, std::string const& item_name, C& container) const {
            auto list = parent.first_element_by_path(name.c_str());

            for (auto& node : list) {
                if (node.type() != pugi::xml_node_type::node_element) {
                    std::cerr << "Warning: unexpected child node type ignored\n";
                    continue;
                }
                if (node.name() != item_name) {
                    std::cerr << "Warning: unexpected child node ignored (" << node.name() << ")\n";
                    continue;
                }

                container.emplace_back();
                operator()(node, container.back());
            }
        }

        void operator()(pugi::xml_node dto, HardwareHostDto& o) const {
            operator()(dto, "HardwareHostID", o.HardwareHostID);
            operator()(dto, "BranchID", o.BranchID);
            operator()(dto, "HardwareHostFriendlyName", o.HardwareHostFriendlyName);
            operator()(dto, "HardwareList", "Hardware", o.HardwareList);
        }

        void operator()(pugi::xml_node parent, std::string const& name, HardwareHostDto& o) const {
            operator()(parent.first_element_by_path(name.c_str()), o);
        }
    };
};

int main() {
    {

        pugi::xml_document _doc;
        Xml::Saver saver;

        HardwareHostDto host = { 1, 1, "kiosk", { { 1, 2, "friendly" } } };
        saver(_doc.root(), "HardwareHost", host);

        _doc.save_file("test.xml");
    }

    {
        HardwareHostDto roundtrip;
        {
            pugi::xml_document _doc;
            _doc.load_file("test.xml");
            Xml::Loader loader;

            loader(_doc.root(), "HardwareHost", roundtrip);
        }

        std::cout << "Read back: " << roundtrip.HardwareHostID << "\n";
        std::cout << "Read back: " << roundtrip.BranchID << "\n";
        std::cout << "Read back: " << roundtrip.HardwareHostFriendlyName << "\n";
        for (auto& h: roundtrip.HardwareList) {
            std::cout << "Item: " << h.HardwareID << ", " << h.HardwareHostID << ", " << h.HardwareFriendlyName << "\n";
        }
    }

}

Который также печатает

Read back: 1
Read back: 1
Read back: kiosk
Item: 2, 1, friendly

И пишетtest.xml:

<?xml version="1.0"?>
<HardwareHost>
    <HardwareHostID>1</HardwareHostID>
    <BranchID>1</BranchID>
    <HardwareHostFriendlyName>kiosk</HardwareHostFriendlyName>
    <HardwareList>
        <Hardware>
            <HardwareHostID>1</HardwareHostID>
            <HardwareID>2</HardwareID>
            <HardwareFriendlyName>friendly</HardwareFriendlyName>
        </Hardware>
    </HardwareList>
</HardwareHost>
 sehe23 нояб. 2017 г., 16:56
Добавлены примерывзлом сериализации также как ииспользуя библиотеку Xml
 sehe24 нояб. 2017 г., 03:57
В интересах абсолютного перегиба, вот небольшой репо, который показывает, как эта штука Pugi могла быть обобщена.github.com/sehe/SimpleSerial Я разделил интерфейс сериализации накрошечный интерфейс с участиемнесколько бэкэндов (реализовано PugiXml, Boost Property Tree (xml / json) и Libxml2), Тест запускает один и тот же тест в обе стороны:github.com/sehe/SimpleSerial/blob/libxml2-prototype/main.cpp
 sehe25 нояб. 2017 г., 10:32
@MarijkeBuurlage Пожалуйста. Не. Это делает этоне-XML, Почему вы думаете, что это нужно? (также см., например,stackoverflow.com/questions/47448864/...)
 Marijke Buurlage25 нояб. 2017 г., 06:42
Есть ли способ удалить "<? xml version =" 1.0 "?>"?
 Marijke Buurlage24 нояб. 2017 г., 10:17
Ты великолепен. Спасибо за отличную поддержку. Извините за поздний ответ, потому что мне только что удалось понять и скомпилировать то, что в коде. Спасибо, сэр, пожалуйста, возьмите свое печенье!

Ваш ответ на вопрос