changeset 1045:0bfeeb6d340f

json to xml conversion with pugixml
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 18 Jul 2014 16:41:10 +0200
parents 6d90e2bcab60
children 00f9f36bcd94
files CMakeLists.txt Core/PrecompiledHeaders.h Core/Toolbox.cpp Core/Toolbox.h Resources/CMake/PugixmlConfiguration.cmake UnitTestsSources/UnitTestsMain.cpp
diffstat 6 files changed, 199 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Thu Jul 17 16:01:41 2014 +0200
+++ b/CMakeLists.txt	Fri Jul 18 16:41:10 2014 +0200
@@ -21,9 +21,6 @@
 SET(ENABLE_JPEG ON CACHE BOOL "Enable JPEG decompression")
 SET(ENABLE_JPEG_LOSSLESS ON CACHE BOOL "Enable JPEG-LS (Lossless) decompression")
 
-# Experimental options
-SET(USE_PLUSTACHE OFF CACHE BOOL "Use the Plustache templating engine (experimental)")
-
 # Advanced parameters to fine-tune linking against system libraries
 SET(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp")
 SET(USE_SYSTEM_GOOGLE_LOG ON CACHE BOOL "Use the system version of Google Log")
@@ -37,7 +34,12 @@
 SET(USE_SYSTEM_CURL ON CACHE BOOL "Use the system version of LibCurl")
 SET(USE_SYSTEM_OPENSSL ON CACHE BOOL "Use the system version of OpenSSL")
 SET(USE_SYSTEM_ZLIB ON CACHE BOOL "Use the system version of ZLib")
+
+# Experimental options
+SET(USE_PLUSTACHE OFF CACHE BOOL "Use the Plustache templating engine (experimental)")
+SET(USE_PUGIXML OFF CACHE BOOL "Use the Pugixml parser (experimental)")
 SET(USE_SYSTEM_PLUSTACHE OFF CACHE BOOL "Use the system version of Plustache (experimental)")
+SET(USE_SYSTEM_PUGIXML OFF CACHE BOOL "Use the system version of Pugixml (experimental)")
 
 # Distribution-specific settings
 SET(USE_GTEST_DEBIAN_SOURCE_PACKAGE OFF CACHE BOOL "Use the sources of Google Test shipped with libgtest-dev (Debian only)")
@@ -223,6 +225,7 @@
 include(${CMAKE_SOURCE_DIR}/Resources/CMake/LuaConfiguration.cmake)
 include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibCurlConfiguration.cmake)
 include(${CMAKE_SOURCE_DIR}/Resources/CMake/PlustacheConfiguration.cmake)
+include(${CMAKE_SOURCE_DIR}/Resources/CMake/PugixmlConfiguration.cmake)
 
 
 if (${ENABLE_SSL})
--- a/Core/PrecompiledHeaders.h	Thu Jul 17 16:01:41 2014 +0200
+++ b/Core/PrecompiledHeaders.h	Fri Jul 18 16:41:10 2014 +0200
@@ -49,6 +49,10 @@
 #include <glog/logging.h>
 #include <json/value.h>
 
+#if ORTHANC_PUGIXML_ENABLED == 1
+#include <pugixml.hpp>
+#endif
+
 #include "Enumerations.h"
 #include "OrthancException.h"
 #include "Toolbox.h"
--- a/Core/Toolbox.cpp	Thu Jul 17 16:01:41 2014 +0200
+++ b/Core/Toolbox.cpp	Fri Jul 18 16:41:10 2014 +0200
@@ -83,6 +83,12 @@
 #endif
 
 
+#if ORTHANC_PUGIXML_ENABLED == 1
+#include "ChunkedBuffer.h"
+#include <pugixml.hpp>
+#endif
+
+
 namespace Orthanc
 {
   static bool finish;
@@ -824,5 +830,126 @@
     return boost::filesystem::exists(path);
   }
 
+
+#if ORTHANC_PUGIXML_ENABLED == 1
+  class ChunkedBufferWriter : public pugi::xml_writer
+  {
+  private:
+    ChunkedBuffer buffer_;
+
+  public:
+    virtual void write(const void *data, size_t size)
+    {
+      if (size > 0)
+      {
+        buffer_.AddChunk(reinterpret_cast<const char*>(data), size);
+      }
+    }
+
+    void Flatten(std::string& s)
+    {
+      buffer_.Flatten(s);
+    }
+  };
+
+
+  static void JsonToXmlInternal(pugi::xml_node& target,
+                                const Json::Value& source,
+                                const std::string& arrayElement)
+  {
+    // http://jsoncpp.sourceforge.net/value_8h_source.html#l00030
+
+    switch (source.type())
+    {
+      case Json::nullValue:
+      {
+        target.append_child(pugi::node_pcdata).set_value("null");
+        break;
+      }
+
+      case Json::intValue:
+      {
+        std::string s = boost::lexical_cast<std::string>(source.asInt());
+        target.append_child(pugi::node_pcdata).set_value(s.c_str());
+        break;
+      }
+
+      case Json::uintValue:
+      {
+        std::string s = boost::lexical_cast<std::string>(source.asUInt());
+        target.append_child(pugi::node_pcdata).set_value(s.c_str());
+        break;
+      }
+
+      case Json::realValue:
+      {
+        std::string s = boost::lexical_cast<std::string>(source.asFloat());
+        target.append_child(pugi::node_pcdata).set_value(s.c_str());
+        break;
+      }
+
+      case Json::stringValue:
+      {
+        target.append_child(pugi::node_pcdata).set_value(source.asString().c_str());
+        break;
+      }
+
+      case Json::booleanValue:
+      {
+        target.append_child(pugi::node_pcdata).set_value(source.asBool() ? "true" : "false");
+        break;
+      }
+
+      case Json::arrayValue:
+      {
+        for (Json::Value::ArrayIndex i = 0; i < source.size(); i++)
+        {
+          pugi::xml_node node = target.append_child();
+          node.set_name(arrayElement.c_str());
+          JsonToXmlInternal(node, source[i], arrayElement);
+        }
+        break;
+      }
+        
+      case Json::objectValue:
+      {
+        Json::Value::Members members = source.getMemberNames();
+
+        for (size_t i = 0; i < members.size(); i++)
+        {
+          pugi::xml_node node = target.append_child();
+          node.set_name(members[i].c_str());
+          JsonToXmlInternal(node, source[members[i]], arrayElement);          
+        }
+
+        break;
+      }
+
+      default:
+        throw OrthancException(ErrorCode_NotImplemented);
+    }
+  }
+
+
+  void Toolbox::JsonToXml(std::string& target,
+                          const Json::Value& source,
+                          const std::string& rootElement,
+                          const std::string& arrayElement)
+  {
+    pugi::xml_document doc;
+
+    pugi::xml_node n = doc.append_child(rootElement.c_str());
+    JsonToXmlInternal(n, source, arrayElement);
+
+    pugi::xml_node decl = doc.prepend_child(pugi::node_declaration);
+    decl.append_attribute("version").set_value("1.0");
+    decl.append_attribute("encoding").set_value("utf-8");
+
+    ChunkedBufferWriter writer;
+    doc.save(writer, "  ", pugi::format_default, pugi::encoding_utf8);
+    writer.Flatten(target);
+  }
+
+#endif
 }
 
--- a/Core/Toolbox.h	Thu Jul 17 16:01:41 2014 +0200
+++ b/Core/Toolbox.h	Fri Jul 18 16:41:10 2014 +0200
@@ -37,6 +37,7 @@
 #include <stdint.h>
 #include <vector>
 #include <string>
+#include <json/json.h>
 
 namespace Orthanc
 {
@@ -136,5 +137,12 @@
     void CreateDirectory(const std::string& path);
 
     bool IsExistingFile(const std::string& path);
+
+#if ORTHANC_PUGIXML_ENABLED == 1
+    void JsonToXml(std::string& target,
+                   const Json::Value& source,
+                   const std::string& rootElement = "root",
+                   const std::string& arrayElement = "item");
+#endif
   }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/CMake/PugixmlConfiguration.cmake	Fri Jul 18 16:41:10 2014 +0200
@@ -0,0 +1,35 @@
+if (USE_PUGIXML)
+  add_definitions(-DORTHANC_PUGIXML_ENABLED=1)
+
+  if (STATIC_BUILD OR NOT USE_SYSTEM_PUGIXML)
+    set(PUGIXML_SOURCES_DIR ${CMAKE_BINARY_DIR}/pugixml-1.4)
+
+    DownloadPackage(
+      "7c56c91cfe3ecdee248a8e4892ef5781"
+      "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/pugixml-1.4.tar.gz"
+      "${PUGIXML_SOURCES_DIR}")
+
+    include_directories(
+      ${PUGIXML_SOURCES_DIR}/src
+      )
+
+    set(PUGIXML_SOURCES
+      ${PUGIXML_SOURCES_DIR}/src/vlog_is_on.cc
+      )
+
+    list(APPEND THIRD_PARTY_SOURCES 
+      ${PUGIXML_SOURCES_DIR}/src/pugixml.cpp
+      )
+
+  else()
+    CHECK_INCLUDE_FILE_CXX(pugixml.h HAVE_PUGIXML_H)
+    if (NOT HAVE_PUGIXML_H)
+      message(FATAL_ERROR "Please install the libpugixml-dev package")
+    endif()
+
+    link_libraries(pugixml)
+  endif()
+
+else()
+  add_definitions(-DORTHANC_PUGIXML_ENABLED=0)
+endif()
--- a/UnitTestsSources/UnitTestsMain.cpp	Thu Jul 17 16:01:41 2014 +0200
+++ b/UnitTestsSources/UnitTestsMain.cpp	Fri Jul 18 16:41:10 2014 +0200
@@ -674,6 +674,25 @@
 }
 
 
+#if ORTHANC_PUGIXML_ENABLED == 1
+TEST(Toolbox, Xml)
+{
+  Json::Value a;
+  a["hello"] = "world";
+  a["42"] = 43;
+  a["b"] = Json::arrayValue;
+  a["b"].append("test");
+  a["b"].append("test2");
+
+  std::string s;
+  Toolbox::JsonToXml(s, a);
+
+  std::cout << s;
+}
+
+#endif
+
+
 int main(int argc, char **argv)
 {
   // Initialize Google's logging library.