Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) boost::property_tree example 5: an even more complex data type

 

boost::property_tree example 5: data type with a std::vector.

 

 

 

 

 

 

Technical facts

 

Application type(s)

Operating system(s) or programming environment(s)

IDE(s):

Project type:

C++ standard:

Compiler(s):

Libraries used:

 

 

 

 

 

Qt project file: CppProperty_treeExample5.pro

 

QT       += core
QT       -= gui
QMAKE_CXXFLAGS += -std=c++11 -Werror #-Wextra
TARGET = CppProperty_treeExample5
CONFIG   += console
CONFIG   -= app_bundle
TEMPLATE = app
SOURCES += main.cpp

 

 

 

 

 

main.cpp

 

#include <cassert>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

//From http://richelbilderbeek.nl/CppVectorToStreamExample2.htm
std::ostream& operator<<(std::ostream& os, const std::vector<std::string>& w)
{
  //Copy the original std::vector
  std::vector<std::string> v = w;
  //Preformat data
  std::for_each(v.begin(),v.end(),
    [&os](std::string& s)
    {
      //The only assertion done on the input
      //Note that users nearly every use bell characters in their text inputs
      assert(std::count(s.begin(),s.end(),'\b') == 0 && "Text must not contain a bell character");
      std::replace(s.begin(),s.end(),' ','\b');
      if (s == "</>") s = "<\b/>";
    }
  );
  //Check data
  #ifndef NDEBUG
  std::for_each(v.begin(),v.end(),
    [&os](const std::string& s)
    {
      assert(s != "</>" && "Text shoule not be '</>' anymore");
      assert(std::count(s.begin(),s.end(),' ') == 0 && "Text should not contain spaces anymore");
    }
  );
  #endif
  //Write start tag
  os << "<>\n";
  //Write data
  std::for_each(v.begin(),v.end(),
    [&os](const std::string& s)
    {
      os << s << '\n';
    }
  );
  //Write end tag
  os << "</>";
  return os;
}

//From http://richelbilderbeek.nl/CppVectorToStreamExample2.htm
std::istream& operator>>(std::istream& is, std::vector<std::string>& v)
{
  //Read start tag
  {
    std::string s; is >> s; assert(s == std::string("<>"));
  }
  //Read data until end tag
  while (1)
  {
    std::string s;
    is >> s;
    if (s == std::string("</>")) return is;
    if (s == "<\b/>") s = "</>";
    std::replace(s.begin(),s.end(),'\b',' ');
    v.push_back(s);
  }
}

///Names is a struct to contain a std::vector<std::string>
///Without it, boost::property_tree cannot parse People
///See commented code below for a Names-less version that will not compile
struct Names
{
  std::vector<std::string> m_names;
};

struct People
{

  void AddName(const std::string& name)
  {
    m_names.m_names.push_back(name);
  }
  const std::vector<std::string>& GetNames() const
  {
    return m_names.m_names;
  }
  void SetNames(const Names& names)
  {
    m_names = names;
  }
  void Load(const std::string &filename)
  {
    boost::property_tree::ptree t;
    boost::property_tree::xml_parser::read_xml(filename,t);
    m_names = t.get<Names>("People.names");
  }
  void Save(const std::string &filename) const
  {
    boost::property_tree::ptree t;
    t.put("People.names", m_names);
    boost::property_tree::xml_parser::write_xml(filename,t);
  }
  private:
  Names m_names;
};

bool operator==(const People& lhs, const People& rhs)
{
  return lhs.GetNames() == rhs.GetNames();
}

std::ostream& operator<<(std::ostream& os, const Names& p)
{
  os << p.m_names;
  return os;
}

std::istream& operator>>(std::istream& is, Names& p)
{
  is >> p.m_names;
  return is;
}

std::ostream& operator<<(std::ostream& os, const People& p)
{
  os << p.GetNames();
  return os;
}

std::istream& operator>>(std::istream& is, People& p)
{
  Names names;
  is >> names; p.SetNames(names);
  return is;
}


int main()
{
  //Test reading and writing of std::vector<std::string>
  //From http://richelbilderbeek.nl/CppVectorToStreamExample2.htm
  {
    //Go ahead, create an entry that breaks the code!
    const std::vector<std::string> v(
      {
        "aahs",
        "aals",
        "abac",
        "abas",
        "</>",
        " </>",
        " </> ",
        "_</>",
        "</>_",
        "</></>",
        "</> </>",
        "</>_</>",
        "abba",
        "abbe",
        "abbs",
        "abed",
        "abet",
        "abid"
      }
    );
    const std::string filename = "tmp.txt";
    //Write to file
    {
      std::ofstream f(filename.c_str());
      f << v;
    }
    //Read from file
    {
      std::vector<std::string> w;
      std::ifstream f(filename.c_str());
      f >> w;
      if (v != w)
      {
        std::copy(w.begin(),w.end(),std::ostream_iterator<std::string>(std::cout,"\n"));
      }
      assert(v == w && "Because the algorithm is excellent, this will never happen B-)");
    }
  }
  //Check writing/reading people to/from stream in plain text
  //Note that this also works, without using boost::property_tree
  const std::string filename = "tmp.txt";
  {
    People p;
    p.AddName("Bilderbikkel");
    p.AddName("Richel Bilderbeek");
    {
      std::ofstream f(filename.c_str());
      f << p;
    }
    {
      std::ifstream f(filename.c_str());
      People q;
      f >> q;
      assert(p == q);

    }
  }
  //Check writing/reading people to/from stream using XML
  {
    People p;
    p.AddName("Bilderbikkel");
    p.AddName("Richel Bilderbeek");
    {
      p.Save(filename);
    }
    {
      People q;
      q.Load(filename);
      assert(p == q);

    }
  }
  //Display tmp.txt
  {
    std::cout << "Displaying '" << filename << "':\n";
    std::ifstream f(filename);
    while(!f.eof())
    {
      std::string s;
      std::getline(f,s);
      std::cout << s << '\n';
    }
  }
}

/* Screen output:

Displaying 'tmp.txt':
<?xml version="1.0" encoding="utf-8"?>
<People><names>&lt;&gt;
Bilderbikkel
RichelBilderbeek
&lt;/&gt;</names></People>

*/

/*
*
*
#include <cassert>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

//From http://richelbilderbeek.nl/CppVectorToStreamExample2.htm
std::ostream& operator<<(std::ostream& os, const std::vector<std::string>& w)
{
  //Copy the original std::vector
  std::vector<std::string> v = w;
  //Preformat data
  std::for_each(v.begin(),v.end(),
    [&os](std::string& s)
    {
      //The only assertion done on the input
      //Note that users nearly every use bell characters in their text inputs
      assert(std::count(s.begin(),s.end(),'\b') == 0 && "Text must not contain a bell character");
      std::replace(s.begin(),s.end(),' ','\b');
      if (s == "</>") s = "<\b/>";
    }
  );
  //Check data
  #ifndef NDEBUG
  std::for_each(v.begin(),v.end(),
    [&os](const std::string& s)
    {
      assert(s != "</>" && "Text shoule not be '</>' anymore");
      assert(std::count(s.begin(),s.end(),' ') == 0 && "Text should not contain spaces anymore");
    }
  );
  #endif
  //Write start tag
  os << "<>\n";
  //Write data
  std::for_each(v.begin(),v.end(),
    [&os](const std::string& s)
    {
      os << s << '\n';
    }
  );
  //Write end tag
  os << "</>";
  return os;
}

//From http://richelbilderbeek.nl/CppVectorToStreamExample2.htm
std::istream& operator>>(std::istream& is, std::vector<std::string>& v)
{
  //Read start tag
  {
    std::string s; is >> s; assert(s == std::string("<>"));
  }
  //Read data until end tag
  while (1)
  {
    std::string s;
    is >> s;
    if (s == std::string("</>")) return is;
    if (s == "<\b/>") s = "</>";
    std::replace(s.begin(),s.end(),'\b',' ');
    v.push_back(s);
  }
}

struct People
{

  void AddName(const std::string& name)
  {
    m_names.push_back(name);
  }
  const std::vector<std::string>& GetNames() const
  {
    return m_names;
  }
  void SetNames(const std::vector<std::string>& names)
  {
    m_names = names;
  }
  void Load(const std::string &filename)
  {
    boost::property_tree::ptree t;
    boost::property_tree::xml_parser::read_xml(filename,t);
    m_names = t.get<std::vector<std::string> >("People.names");
  }
  void Save(const std::string &filename) const
  {
    boost::property_tree::ptree t;
    t.put("People.names", this->m_names);
    boost::property_tree::xml_parser::write_xml(filename,t);
  }
  private:
  std::vector<std::string> m_names;
};

bool operator==(const People& lhs, const People& rhs)
{
  return lhs.GetNames() == rhs.GetNames();
}

std::ostream& operator<<(std::ostream& os, const People& p)
{
  os << p.GetNames();
  return os;
}

std::istream& operator>>(std::istream& is, People& p)
{
  std::vector<std::string> names;
  is >> names; p.SetNames(names);
  return is;
}


int main()
{
  //Test reading and writing of std::vector<std::string>
  //From http://richelbilderbeek.nl/CppVectorToStreamExample2.htm
  {
    //Go ahead, create an entry that breaks the code!
    const std::vector<std::string> v(
      {
        "aahs",
        "aals",
        "abac",
        "abas",
        "</>",
        " </>",
        " </> ",
        "_</>",
        "</>_",
        "</></>",
        "</> </>",
        "</>_</>",
        "abba",
        "abbe",
        "abbs",
        "abed",
        "abet",
        "abid"
      }
    );
    const std::string filename = "tmp.txt";
    //Write to file
    {
      std::ofstream f(filename.c_str());
      f << v;
    }
    //Read from file
    {
      std::vector<std::string> w;
      std::ifstream f(filename.c_str());
      f >> w;
      if (v != w)
      {
        std::copy(w.begin(),w.end(),std::ostream_iterator<std::string>(std::cout,"\n"));
      }
      assert(v == w && "Because the algorithm is excellent, this will never happen B-)");
    }
  }
  //Check writing/reading people to/from stream in plain text
  //Note that this also works, without using boost::property_tree
  const std::string filename = "tmp.txt";
  {
    People p;
    p.AddName("Bilderbikkel");
    p.AddName("Richel Bilderbeek");
    {
      std::ofstream f(filename.c_str());
      f << p;
    }
    {
      std::ifstream f(filename.c_str());
      People q;
      f >> q;
      assert(p == q);

    }
  }
  //Check writing/reading people to/from stream using XML
  {
    People p;
    p.AddName("Bilderbikkel");
    p.AddName("Richel Bilderbeek");
    {
      p.Save(filename);
    }
    {
      People q;
      q.Load(filename);
      assert(p == q);

    }
  }
  //Display tmp.txt
  {
    std::cout << "Displaying '" << filename << "':\n";
    std::ifstream f(filename);
    while(!f.eof())
    {
      std::string s;
      std::getline(f,s);
      std::cout << s << '\n';
    }
  }
}
*/

 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict

This page has been created by the tool CodeToHtml