Go back to Richel Bilderbeek's homepage.

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

 

 

 

 

 

(C++) ToXml

 

Technical facts

 

Operating system(s) or programming environment(s)

IDE(s):

Project type:

C++ standard:

Compiler(s):

Libraries used:

 

 

 

 

 

Qt project file: ./CppToXml/CppToXml.pro

 

TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += main.cpp


#
#
# Type of compile
#
#

CONFIG(release, debug|release) {
  DEFINES += NDEBUG NTRACE_BILDERBIKKEL
}

QMAKE_CXXFLAGS += -std=c++11 -Wall -Wextra -Weffc++

unix {
  QMAKE_CXXFLAGS += -Werror
}

#
#
# Boost
#
#

win32 {
  INCLUDEPATH += \
    ../../Libraries/boost_1_54_0
}

 

 

 

 

 

./CppToXml/main.cpp

 

#include <cassert>
#include <string>
#include <sstream>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
#pragma GCC diagnostic pop

///Convert a std::string to single-line XML
///For example, a std::string with tag name "cat_name" and content "Kitty" becomes
/// <cat_name>Kitty</cat_name>
///The data can be converted back with XmlToStr
template <class T, class U>
const std::string ToXml(
  const T& tag_name,
  const U& content)
{
  std::stringstream s;
  s << "<"  << tag_name << ">" << content << "</" << tag_name << ">";
  //No test here, as ToXml is used in testing FromXml
  return s.str();
}

///Convert a std::string to single-line XML
///For example, a std::string with tag name "cat_name" and content "Kitty" becomes
/// <cat_name>Kitty</cat_name>
///The data can be converted back with XmlToStr
template <class T, class U>
const std::string ToXml(
  const T& tag_name,
  const U& content,
  const std::function<std::string(const T&)> tag_to_str_function,
  const std::function<std::string(const U&)> tag_to_content_function
  )
{
  std::stringstream s;
  s
    << "<"  << tag_to_str_function(tag_name) << ">"
    << tag_to_content_function(content)
    << "</" << tag_to_str_function(tag_name) << ">";
  //No test here, as ToXml is used in testing FromXml
  return s.str();
}

///Convert a single-line XML to its content and its tag name
///For example, the XML line "<cat_name>Kitty</cat_name>"
///becomes a std::pair with elements {"cat_name","Kitty"}
///The data can be converted back with ToXml
template <class T, class U>
const std::pair<T,U> FromXml(const std::string& xml)
{
  assert(!xml.empty());
  assert(xml[0] == '<');
  assert(xml[xml.size() - 1] == '>');
  assert(xml.find('>') != std::string::npos);
  const int tag_name_sz = static_cast<int>(xml.find('>')) - 1;
  const std::string tag_name = xml.substr(1,tag_name_sz);

  assert(xml.find_last_of('/') != std::string::npos);
  const int content_sz = static_cast<int>(xml.find_last_of('/')) - tag_name_sz - 3;
  const std::string content = xml.substr(tag_name.size() + 2,content_sz);
  const std::pair<T,U> p {
    boost::lexical_cast<T>(tag_name),
    boost::lexical_cast<U>(content)
  };
  assert(ToXml(p.first,p.second) == xml);
  return p;
}

///Convert a single-line XML to its content and its tag name
///For example, the XML line "<cat_name>Kitty</cat_name>"
///becomes a std::pair with elements {"cat_name","Kitty"}
///The data can be converted back with ToXml
template <class T, class U>
const std::pair<T,U> FromXml(
  const std::string& xml,
  const std::function<T(const std::string&)> str_to_tag_function,
  const std::function<U(const std::string&)> str_to_content_function
  )
{
  assert(!xml.empty());
  assert(xml[0] == '<');
  assert(xml[xml.size() - 1] == '>');
  assert(xml.find('>') != std::string::npos);
  const int tag_name_sz = static_cast<int>(xml.find('>')) - 1;
  const std::string tag_name = xml.substr(1,tag_name_sz);

  assert(xml.find_last_of('/') != std::string::npos);
  const int content_sz = static_cast<int>(xml.find_last_of('/')) - tag_name_sz - 3;
  const std::string content = xml.substr(tag_name.size() + 2,content_sz);
  const std::pair<T,U> p {
    str_to_tag_function(tag_name),
    str_to_content_function(content)
  };
  //Cannot do this debug check anymore, as one would need
  //a tag_to_str_function and content_to_str_function:
  //assert(ToXml(p.first,p.second,tag_to_str_function,content_to_str_function) == xml);
  return p;
}


int main()
{
  //tag: std::string, content: std::string
  {
    typedef std::string TagType;
    typedef std::string ContentType;
    const TagType     tag_name { "name"  };
    const ContentType content  { "Kitty" };
    const std::string xml { ToXml(tag_name,content) };
    const std::pair<TagType,ContentType> p { FromXml<TagType,ContentType>(xml) };
    assert(p.first  == tag_name);
    assert(p.second == content);
  }
  //tag: int, content: std::string
  {
    typedef int TagType;
    typedef std::string ContentType;
    const TagType     tag_name { 42  };
    const ContentType content  { "The answer" };
    const std::string xml { ToXml(tag_name,content) };
    const std::pair<TagType,ContentType> p { FromXml<TagType,ContentType>(xml) };
    assert(p.first  == tag_name);
    assert(p.second == content);
  }
  //tag: int, content: std::string
  {
    typedef int ContentType;
    typedef std::string TagType;
    const TagType     tag_name { "The answer" };
    const ContentType content  { 42 };
    const std::string xml { ToXml(tag_name,content) };
    const std::pair<TagType,ContentType> p { FromXml<TagType,ContentType>(xml) };
    assert(p.first  == tag_name);
    assert(p.second == content);
  }
  //tag: int, content: int
  {
    typedef std::string TagType;
    typedef int ContentType;
    const TagType     tag_name { 123 };
    const ContentType content  { 456 };
    const std::string xml { ToXml(tag_name,content) };
    const std::pair<TagType,ContentType> p { FromXml<TagType,ContentType>(xml) };
    assert(p.first  == tag_name);
    assert(p.second == content);
  }
  //tag: std::string, content: boost::shared_ptr<const std::string>
  {
    typedef std::string TagType;
    typedef boost::shared_ptr<const std::string> ContentType;
    const TagType     tag_name { "name" };
    const ContentType content  { boost::shared_ptr<const std::string>(new std::string("Kitty")) };

    //Convert tag and content to XML
    const std::function<std::string(const TagType&)> tag_to_str_function {
      [](const TagType& t) { return t; }
    };
    const std::function<std::string(const ContentType&)> content_to_str_function {
      [](const ContentType& c) { return *c; }
    };

    const std::string xml {
      ToXml(tag_name,content,tag_to_str_function,content_to_str_function)
    };

    //Convert XML back to its tag and content
    //with custom functions
    const std::function<TagType(const std::string&)> str_to_tag_function {
      [](const std::string& s) { return s; }
    };
    const std::function<ContentType(const std::string&)> str_to_content_function {
      [](const std::string& s) { return boost::shared_ptr<const std::string>(new std::string(s)); }
    };

    //Check both conversion functions
    //Cannot simply compare to tag_name and content, as these may be of any type
    assert(tag_to_str_function(str_to_tag_function(tag_to_str_function(tag_name)))
      ==   tag_to_str_function(                                        tag_name));
    assert(content_to_str_function(str_to_content_function(content_to_str_function(content)))
      ==   content_to_str_function(                                                content));

    const std::pair<TagType,ContentType> p {
      FromXml<TagType,ContentType>(
        xml,
        str_to_tag_function,
        str_to_content_function
      )
    };

    //Cannot simply compare to tag_name and content, as these may be of any type
    assert(tag_to_str_function(    p.first ) == tag_to_str_function(    tag_name));
    assert(content_to_str_function(p.second) == content_to_str_function(content ));
  }

  //tag: int, content: boost::shared_ptr<const std::string>
  {
    typedef int TagType;
    typedef boost::shared_ptr<const std::string> ContentType;
    const TagType     tag_name { 123 };
    const ContentType content  { boost::shared_ptr<const std::string>(new std::string("one-two-three")) };

    //Convert tag and content to XML
    const std::function<std::string(const TagType&)> tag_to_str_function {
      [](const TagType& t) { return boost::lexical_cast<std::string>(t); }
    };
    const std::function<std::string(const ContentType&)> content_to_str_function {
      [](const ContentType& c) { return *c; }
    };

    const std::string xml {
      ToXml(tag_name,content,tag_to_str_function,content_to_str_function)
    };

    //Convert XML back to its tag and content
    //with custom functions
    const std::function<TagType(const std::string&)> str_to_tag_function {
      [](const std::string& s) { return boost::lexical_cast<TagType>(s); }
    };
    const std::function<ContentType(const std::string&)> str_to_content_function {
      [](const std::string& s) { return boost::shared_ptr<const std::string>(new std::string(s)); }
    };

    //Check both conversion functions
    //Cannot simply compare to tag_name and content, as these may be of any type
    assert(tag_to_str_function(str_to_tag_function(tag_to_str_function(tag_name)))
      ==   tag_to_str_function(                                        tag_name));
    assert(content_to_str_function(str_to_content_function(content_to_str_function(content)))
      ==   content_to_str_function(                                                content));

    const std::pair<TagType,ContentType> p {
      FromXml<TagType,ContentType>(
        xml,
        str_to_tag_function,
        str_to_content_function
      )
    };

    //Cannot simply compare to tag_name and content, as these may be of any type
    assert(tag_to_str_function(    p.first ) == tag_to_str_function(    tag_name));
    assert(content_to_str_function(p.second) == content_to_str_function(content ));
  }
}

 

 

 

 

 

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