使用XML宽存档增强juce :: String的反序列化问题

时间:2011-05-25 14:34:46

标签: c++ serialization boost

我正在使用boost :: serialize来序列化我使用f.i的文档。一个juce :: String。像这样:

template<class Archive>
void serialize( Archive & ar, const unsigned int version )
{
    ar & boost::serialization::make_nvp("title", m_docTitle);
    ...
}

对于boost :: serialize接受juce :: String作为基本类型我做了:

#include <boost/serialization/string.hpp>

template<class IStream>
inline IStream& operator >> (IStream& stream, juce::String& s)
{
    std::wstring t;
    stream >> t;
    s = juce::String(t.c_str());
    return stream;
}

BOOST_CLASS_IMPLEMENTATION(juce::String, boost::serialization::primitive_type)

编译得很好。序列化工作正常,我得到XML中的条目:

<title>DocumentTitle</title>

应该如此。但是,当反序列化时,我可以追踪&gt;&gt;返回的字符串是:

"DocumentTitle</title>"

即。一些XML已被“咀嚼”,后来当然会导致“输入流错误”异常。

最奇怪的部分是,直到一周前我才开始工作...... :(我不知道是什么让它现在不起作用......

编辑:显示重现行为的一个小示例代码,只有依赖是boost:

#include <boost/serialization/serialization.hpp>
#include <boost/serialization/string.hpp>

#include <boost/archive/xml_woarchive.hpp>
#include <boost/archive/xml_wiarchive.hpp>
#include <sstream>

class JuceString
{
public:
    JuceString(const std::wstring& str = L"") : m_str(str) {;}
    JuceString(const JuceString& other) : m_str(other.m_str) {;}
    JuceString& operator = (const JuceString& other)
    {
        if (this != &other)
        {
            m_str = other.m_str;
        }
        return *this;
    }
    const wchar_t* toWideCharPointer() const {
        return m_str.c_str();
    }

private:
    std::wstring m_str;
};

template <class OStream>
OStream& operator<< (OStream& stream, const JuceString& stringToWrite)
{
    return stream << stringToWrite.toWideCharPointer();
}

template <class IStream>
IStream& operator>> (IStream& stream, JuceString& s)
{
    std::wstring t;
    stream >> t;
    s = JuceString(t.c_str());
    return stream;
}

BOOST_CLASS_IMPLEMENTATION(JuceString, boost::serialization::primitive_type)


class Doc
{
    friend class boost::serialization::access;

    template<class Archive>
    void serialize( Archive & ar, const unsigned int version )
    {
        ar & boost::serialization::make_nvp("title", m_title);
    }

public:
    Doc() {;}
    Doc(const std::wstring& s) : m_title(s) {;}

private:
    JuceString m_title;
};


int main (int argc, char* argv[])
{
    std::wstringstream stream;
    {
        // Serializing document
        Doc doc(L"DocumentTitle");
        boost::archive::xml_woarchive oa(stream);
        oa << boost::serialization::make_nvp("Document", doc);
    }
    {
        // Deserializing document
        Doc doc;
        try
        {
            boost::archive::xml_wiarchive ia(stream);
            ia >> boost::serialization::make_nvp("Document", doc);
        }
        catch (std::exception& e)
        {
            std::cerr << e.what() << std::endl;
        }

    }
    return 0;
}

使用文本存档可以很好地兼顾......

3 个答案:

答案 0 :(得分:2)

最后我通过使用boost basic_xml_grammar解析运算符&gt;&gt;中的字符串,使其工作(对于XML存档而言)。 ,像这样:

typedef boost::archive::basic_xml_grammar<wchar_t> xml_wgrammar;

template <class IStream>
IStream& operator>> (IStream& stream, JuceString& s)
{
    std::wstring t;
    xml_wgrammar grammar;
    if (!grammar.parse_string(stream, t))
    {
        boost::serialization::throw_exception(
            boost::archive::xml_archive_exception(boost::archive::xml_archive_exception::xml_archive_parsing_error)
        );
    }
    s = JuceString(t.c_str());
    return stream;
}

这将确保正确解析字符串。

答案 1 :(得分:1)

问题出在您的operator >>

当你这样做时:

std::wstring t;
stream >> t;

你读到下一个空格。在结束标记之后的XML中,因此您正在阅读提升期望能够在那里阅读的流的一部分。

解决方案是强制将额外空间强制输出,或修改operator >>以拒绝读取任何类似'&lt;'的内容。我的猜测是,之前你在保存和恢复的字符串中有一个额外的空间。

假设您可以从std::wstring设置/分配并获取某些可用于创建std :: wstring的原始值,这可以在我的机器上运行:

#include <boost/serialization/split_free.hpp>

...

namespace boost {
namespace serialization {

  template<class Archive>
  void load(Archive & ar, JuceString & j, const unsigned int version)
  {
    std::wstring tmp;
    ar & boost::serialization::make_nvp("value", tmp);
    j = tmp;
  }

  template<class Archive>
  void save(Archive & ar, const JuceString & j, const unsigned int version)
  {
    const std::wstring tmp(j.toWideCharPointer());
    ar & boost::serialization::make_nvp("value", tmp);
  }

} // namespace serialization                                                                                                                                            
} // namespace boost                                                                                                                                                    
BOOST_SERIALIZATION_SPLIT_FREE(JuceString)

这省去了编写operator >>的需要,并让boost处理直接读取/写入wstring到存档。您只需要编写一次,这样可以避免重复问题,然后您可以随时使用JuceString

答案 2 :(得分:0)

我不知道是否有答案,但在比较我的工作区中的代码以序列化ATL CString时,我有以下内容:

inline void serialize(Archive & ar, CString & s, const unsigned int file_version) 
{
    std::wstring ss( s );
    ar & BOOST_SERIALIZATION_NVP(ss);
    s = ss.c_str();
}

我想知道你是否可以在operator <<中做这样的事情 - 不确定这个解决方案是否适用于你。如果没有,请提前道歉。