From 2ef68d9f16176de310793d2b5c93ef73a4ca84c1 Mon Sep 17 00:00:00 2001
From: Markus Frank <Markus.Frank@cern.ch>
Date: Thu, 16 Mar 2017 13:32:06 +0100
Subject: [PATCH] Add first version of JSON interpreter

---
 DDCore/CMakeLists.txt           |   2 +-
 DDCore/include/JSON/Elements.h  | 505 ++++++++++++++++++++++++++++++++
 DDCore/include/JSON/Evaluator.h |  24 ++
 DDCore/include/JSON/Printout.h  |  24 ++
 DDCore/include/JSON/config.h    |  35 +++
 DDCore/src/JSON/Elements.cpp    | 502 +++++++++++++++++++++++++++++++
 6 files changed, 1091 insertions(+), 1 deletion(-)
 create mode 100644 DDCore/include/JSON/Elements.h
 create mode 100644 DDCore/include/JSON/Evaluator.h
 create mode 100644 DDCore/include/JSON/Printout.h
 create mode 100644 DDCore/include/JSON/config.h
 create mode 100644 DDCore/src/JSON/Elements.cpp

diff --git a/DDCore/CMakeLists.txt b/DDCore/CMakeLists.txt
index d680fcd21..fc752dc5a 100644
--- a/DDCore/CMakeLists.txt
+++ b/DDCore/CMakeLists.txt
@@ -42,7 +42,7 @@ dd4hep_add_package_library ( DDParsers
 
 #---Generate DDCore Library-------------------------------------------------------
 dd4hep_add_package_library ( DDCore
-  SOURCES        src/*.cpp src/XML/*.cpp
+  SOURCES        src/*.cpp src/XML/*.cpp src/JSON/*.cpp
   GENERATED      G__DD4hep.cxx 
   INCLUDE_DIRS   ${GaudiPluginService_INCLUDE_DIRS}
   LINK_LIBRARIES DDParsers ${GaudiPluginService_LIBRARIES}
diff --git a/DDCore/include/JSON/Elements.h b/DDCore/include/JSON/Elements.h
new file mode 100644
index 000000000..580855a11
--- /dev/null
+++ b/DDCore/include/JSON/Elements.h
@@ -0,0 +1,505 @@
+//==========================================================================
+//  AIDA Detector description implementation for LCD
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+#ifndef DDCORE_DD4HEP_JSON_ELEMENTS_H
+#define DDCORE_DD4HEP_JSON_ELEMENTS_H
+
+// C/C++ include files
+#include <cmath>
+#include <string>
+#include <vector>
+#include <stdexcept>
+
+// Framework include files
+#include "JSON/config.h"
+
+#ifndef RAD_2_DEGREE
+#define RAD_2_DEGREE 57.295779513082320876798154814105
+#endif
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+/// Namespace for the AIDA detector description toolkit
+namespace DD4hep {
+
+  /// Namespace for the AIDA detector description toolkit supporting JSON utilities
+  namespace JSON {
+
+    typedef const JsonAttr* Attribute;
+
+    typedef const std::string& CSTR;
+
+    /// Dump DOM tree of a document
+    void dumpTree(JsonDocument* doc);
+
+    /// Convert json attribute to STL string  \ingroup DD4HEP_JSON
+    std::string _toString(const Attribute attr);
+    /// Convert json string to STL string  \ingroup DD4HEP_JSON
+    std::string _toString(const JsonChar *toTranscode);
+    /// Do-nothing version. Present for completeness and argument interchangeability  \ingroup DD4HEP_JSON
+    std::string _toString(const char* s);
+    /// Do-nothing version. Present for completeness and argument interchangeability  \ingroup DD4HEP_JSON
+    std::string _toString(const std::string& s);
+    /// Format unsigned long integer to string with arbitrary format  \ingroup DD4HEP_JSON
+    std::string _toString(unsigned long i, const char* fmt = "%lu");
+    /// Format unsigned integer (32 bits) to string with arbitrary format  \ingroup DD4HEP_JSON
+    std::string _toString(unsigned int i, const char* fmt = "%u");
+    /// Format signed integer (32 bits) to string with arbitrary format  \ingroup DD4HEP_JSON
+    std::string _toString(int i, const char* fmt = "%d");
+    /// Format signed long integer to string with arbitrary format  \ingroup DD4HEP_JSON
+    std::string _toString(long i, const char* fmt = "%ld");
+    /// Format single procision float number (32 bits) to string with arbitrary format  \ingroup DD4HEP_JSON
+    std::string _toString(float d, const char* fmt = "%.17e");
+    /// Format double procision float number (64 bits) to string with arbitrary format  \ingroup DD4HEP_JSON
+    std::string _toString(double d, const char* fmt = "%.17e");
+    /// Format void pointer (64 bits) to string with arbitrary format  \ingroup DD4HEP_JSON
+    std::string _ptrToString(const void* p, const char* fmt = "%p");
+    /// Format void pointer (64 bits) to string with arbitrary format  \ingroup DD4HEP_JSON
+    template <typename T> std::string _toString(const T* p, const char* fmt = "%p")
+    {      return _ptrToString((void*)p,fmt);       }
+
+    /// Helper function to populate the evaluator dictionary  \ingroup DD4HEP_JSON
+    void _toDictionary(const JsonChar* name, const JsonChar* value);
+    /// Helper function to populate the evaluator dictionary  \ingroup DD4HEP_JSON
+    void _toDictionary(const std::string& name, const JsonChar* value)
+    {  _toDictionary(name, value);  }
+    /// Helper function to populate the evaluator dictionary  \ingroup DD4HEP_JSON
+    template <typename T> void _toDictionary(const JsonChar* name, T value);
+
+    /// Helper function to populate the evaluator dictionary  \ingroup DD4HEP_JSON
+    void _toDictionary(const JsonChar* name, float  value);
+    /// Helper function to populate the evaluator dictionary  \ingroup DD4HEP_JSON
+    void _toDictionary(const JsonChar* name, double value);
+    /// Helper function to lookup environment from the expression evaluator
+    std::string getEnviron(const std::string& env);
+
+    /// Conversion function from raw unicode string to bool  \ingroup DD4HEP_JSON
+    bool _toBool(const JsonChar* value);
+    /// Conversion function from raw unicode string to int  \ingroup DD4HEP_JSON
+    int _toInt(const JsonChar* value);
+    /// Conversion function from raw unicode string to long  \ingroup DD4HEP_JSON
+    long _toLong(const JsonChar* value);
+    /// Conversion function from raw unicode string to float  \ingroup DD4HEP_JSON
+    float _toFloat(const JsonChar* value);
+    /// Conversion function from raw unicode string to double  \ingroup DD4HEP_JSON
+    double _toDouble(const JsonChar* value);
+
+    /// Class describing a list of JSON nodes
+    /**
+     *  Definition of a "list" of json elements hanging of the parent.
+     *  The list allows iterations, which can be restarted.
+     *  Please not: Copies are not entirely free, since the
+     *  string tag need to be replicated using strdup/free
+     *  (or when using xerces the corresponding unicode routines).
+     *
+     *  \author   M.Frank
+     *  \version  1.0
+     *  \ingroup DD4HEP_JSON
+     */
+    class NodeList {
+    public:
+      typedef std::pair<JsonElement::second_type::assoc_iterator,JsonElement::second_type::assoc_iterator> iter_t;
+      std::string    m_tag;
+      JsonElement*   m_node;
+      mutable iter_t m_ptr;
+
+      /// Copy constructor
+      NodeList(const NodeList& l);
+      /// Initializing constructor
+      NodeList(JsonElement* frst, const std::string& tag);
+      /// Default destructor
+      ~NodeList();
+      /// Reset the nodelist - e.g. restart iteration from beginning
+      JsonElement* reset();
+      /// Advance to next element
+      JsonElement* next() const;
+      /// Go back to previous element
+      JsonElement* previous() const;
+      /// Assignment operator
+      NodeList& operator=(const NodeList& l);
+    };
+
+    /// Class to easily access the properties of single JsonElements.
+    /**
+     *  Note: The assignmant operator as well as the copy constructor
+     *  do not have to be implemented, they are aut-generated by the compiler!
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_JSON
+     */
+    class Handle_t {
+    public:
+      // Abbreviation for internal use
+      typedef JsonElement* Elt_t;
+
+      /// The pointer to the JsonElement
+      mutable Elt_t m_node;
+
+      /// Initializing constructor
+      Handle_t(Elt_t e = 0)
+        : m_node(e) {
+      }
+      /// Direct access to the JsonElement using the operator->
+      Elt_t operator->() const {
+        return m_node;
+      }
+      /// Direct access to the JsonElement by dereferencing
+      operator Elt_t() const {
+        return m_node;
+      }
+      /// Direct access to the JsonElement by function
+      Elt_t ptr() const {
+        return m_node;
+      }
+      /// Clone the DOMelement - with the option of a deep copy
+      Handle_t clone(JsonDocument* new_doc) const;
+
+      /// Unicode text access to the element's tag. Tis must be wrong ....
+      const JsonChar* rawTag() const;
+      /// Unicode text access to the element's text
+      const JsonChar* rawText() const;
+      /// Unicode text access to the element's value
+      const JsonChar* rawValue() const;
+      /// Text access to the element's tag
+      std::string tag() const {
+        return _toString(rawTag());
+      }
+      /// Text access to the element's text
+      std::string text() const {
+        return _toString(rawText());
+      }
+      /// Text access to the element's value
+      std::string value() const {
+        return _toString(rawValue());
+      }
+
+      /*** DOM Attribute handling
+       */
+      /// Access attribute name (throws exception if not present)
+      const JsonChar* attr_name(const Attribute attr) const;
+      /// Access attribute value by the attribute  (throws exception if not present)
+      const JsonChar* attr_value(const Attribute attr) const;
+      /// Access attribute value by the attribute's unicode name (throws exception if not present)
+      const JsonChar* attr_value(const JsonChar* attr) const;
+      /// Access attribute value by the attribute's unicode name (no exception thrown if not present)
+      const JsonChar* attr_value_nothrow(const JsonChar* attr) const;
+
+      /// Access attribute pointer by the attribute's unicode name (throws exception if not present)
+      Attribute attr_ptr(const JsonChar* attr) const;
+      /// Access attribute pointer by the attribute's unicode name (no exception thrown if not present)
+      Attribute attr_nothrow(const JsonChar* tag) const;
+      /// Check for the existence of a named attribute
+      bool hasAttr(const JsonChar* t) const;
+      /// Retrieve a collection of all attributes of this DOM element
+      std::vector<Attribute> attributes() const;
+      /// Access typed attribute value by the JsonAttr
+      template <class T> T attr(const Attribute a) const {
+        return this->attr<T>(this->attr_name(a));
+      }
+      /// Access typed attribute value by it's unicode name
+      template <class T> T attr(const JsonChar* name) const;
+
+      /*** DOM Element child handling
+       */
+      /// Check the existence of a child with a given tag name
+      bool hasChild(const JsonChar* tag) const;
+      /// Access a single child by it's tag name (unicode)
+      Handle_t child(const JsonChar* tag, bool throw_exception = true) const;
+      /// Access a group of children identified by the same tag name
+      NodeList children(const JsonChar* tag) const;
+      /// Access the number of children of this DOM element with a given tag name
+      size_t numChildren(const JsonChar* tag, bool throw_exception) const;
+      /// Access the element's parent element
+      //Handle_t parent() const;
+    };
+
+#define INLINE inline
+    typedef const JsonChar* cpJsonChar;
+
+    template <> INLINE Attribute Handle_t::attr<Attribute>(const JsonChar* tag_value) const {
+      return attr_ptr(tag_value);
+    }
+
+    template <> INLINE cpJsonChar Handle_t::attr<cpJsonChar>(const JsonChar* tag_value) const {
+      return attr_value(tag_value);
+    }
+
+    template <> INLINE bool Handle_t::attr<bool>(const JsonChar* tag_value) const {
+      return _toBool(attr_value(tag_value));
+    }
+
+    template <> INLINE int Handle_t::attr<int>(const JsonChar* tag_value) const {
+      return _toInt(attr_value(tag_value));
+    }
+    
+    template <> INLINE long Handle_t::attr<long>(const JsonChar* tag_value) const {
+      return _toLong(attr_value(tag_value));
+    }
+
+    template <> INLINE float Handle_t::attr<float>(const JsonChar* tag_value) const {
+      return _toFloat(attr_value(tag_value));
+    }
+
+    template <> INLINE double Handle_t::attr<double>(const JsonChar* tag_value) const {
+      return _toDouble(attr_value(tag_value));
+    }
+
+    template <> INLINE std::string Handle_t::attr<std::string>(const JsonChar* tag_value) const {
+      return _toString(attr_value(tag_value));
+    }
+
+    /// Class to support the access to collections of JsonNodes (or JsonElements)
+    /**
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_JSON
+     */
+    class Collection_t : public Handle_t {
+    public:
+      /// Reference to the list of child nodes
+      NodeList m_children;
+      /// Constructor over JsonElements with a given tag name
+      Collection_t(Handle_t node, const char* tag);
+      /// Constructor over JsonElements in a node list
+      Collection_t(NodeList children);
+      /// Reset the collection object to restart the iteration
+      Collection_t& reset();
+      /// Access the collection size. Avoid this call -- sloooow!
+      size_t size() const;
+      /// Operator to advance the collection (pre increment)
+      void operator++() const;
+      /// Operator to advance the collection (post increment)
+      void operator++(int) const;
+      /// Operator to advance the collection (pre decrement)
+      void operator--() const;
+      /// Operator to advance the collection (post decrement)
+      void operator--(int) const;
+      /// Access to current element
+      Elt_t current() const {
+        return m_node;
+      }
+      /// Helper function to throw an exception
+      void throw_loop_exception(const std::exception& e) const;
+      /// Loop processor using function object
+      template <class T> void for_each(T oper) const {
+        try {
+          for (const Collection_t& c = *this; c; ++c)
+            oper(*this);
+        }
+        catch (const std::exception& e) {
+          throw_loop_exception(e);
+        }
+      }
+      /// Loop processor using function object
+      template <class T> void for_each(const JsonChar* tag_name, T oper) const {
+        try {
+          for (const Collection_t& c = *this; c; ++c)
+            Collection_t(c.m_node, tag_name).for_each(oper);
+        }
+        catch (const std::exception& e) {
+          throw_loop_exception(e);
+        }
+      }
+    };
+
+    /// Class supporting the basic functionality of an JSON document
+    /**
+     *  User class encapsulating a DOM document.
+     *  Nothing special - normal handle around pointer.
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_JSON
+     */
+    class Document {
+    public:
+      typedef JsonDocument* DOC;
+      DOC m_doc;
+
+      /// Constructor
+      Document(DOC d) : m_doc(d) {
+      }
+      /// Auto-conversion to DOM document
+      operator DOC() const {
+        return m_doc;
+      }
+      /// Accessot to DOM document behaviour using arrow operator
+      DOC operator->() const {
+        return m_doc;
+      }
+      /// Accessot to DOM document behaviour
+      DOC ptr() const {
+        return m_doc;
+      }
+    };
+
+    /// Class supporting the basic functionality of an JSON document including ownership
+    /**
+     *  User class encapsulating a DOM document.
+     *  Nothing special - normal handle around pointer.
+     *  Contrary to the Document class, on destruction the
+     *  JSON document shall be destroyed and the corresponding
+     *  resources released.
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_JSON
+     */
+    class DocumentHolder : public Document {
+    public:
+      /// Default Constructor
+      DocumentHolder() : Document(0) {
+      }
+      /// Constructor
+      DocumentHolder(DOC d) : Document(d) {
+      }
+      /// Assign new document. Old document is dropped.
+      DocumentHolder& assign(DOC d);
+      /// Standard destructor - releases the document
+      virtual ~DocumentHolder();
+    };
+
+    /// User abstraction class to manipulate JSON elements within a document
+    /**
+     *  User class encapsulating a DOM element
+     *  using the Handle helper.
+     *  This is the main class we interact with when
+     *  analysing the json documents for constructing
+     *  sub-detectors etc.
+     *
+     *  \author  M.Frank
+     *  \version 1.0
+     *  \ingroup DD4HEP_JSON
+     */
+    class Element {
+    public:
+      /// Simplification type declarations
+      typedef Handle_t::Elt_t Elt_t;
+
+      /// The underlying object holding the JsonElement pointer
+      Handle_t m_element;
+
+      /// Constructor from JsonElement handle
+      Element(const Handle_t& e) : m_element(e)          {      }
+      /// Constructor from JsonElement handle
+      Element(const Element& e) : m_element(e.m_element) {      }
+      /// Constructor from DOM document entity
+      //Element(const Document& document, const JsonChar* type);
+      /// Access the hosting document handle of this DOM element
+      //Document document() const;
+
+      /// operator bool: check handle validity
+      operator bool() const {
+        return 0 != m_element.ptr();
+      }
+      /// operator NOT: check handle validity
+      bool operator!() const {
+        return 0 == m_element.ptr();
+      }
+      /// Assignment operator
+      Element& operator=(const Element& c)  {
+        m_element = c.m_element;
+        return *this;
+      }
+      /// Assignment operator
+      Element& operator=(Handle_t handle)  {
+        m_element = handle;
+        return *this;
+      }
+      /// Automatic conversion to DOM element handle
+      operator Handle_t() const {
+        return m_element;
+      }
+      /// Automatic conversion to JsonElement pointer
+      operator Elt_t() const {
+        return m_element;
+      }
+      /// Access to JsonElement pointer
+      Elt_t ptr() const {
+        return m_element;
+      }
+#if 0
+      /// Access the JsonElements parent
+      Handle_t parent()  const   {
+        return m_element.parent();
+      }
+      /// Access the JsonElements parent
+      Elt_t parentElement()  const;
+#endif
+      /// Access the tag name of this element
+      std::string tag() const {
+        return m_element.tag();
+      }
+      /// Access the tag name of this element
+      const JsonChar* tagName() const {
+        return m_element.rawTag();
+      }
+      /// Access the tag name of this element
+      std::string text() const {
+        return m_element.text();
+      }
+      /// Check for the existence of a named attribute
+      bool hasAttr(const JsonChar* name) const {
+        return m_element.hasAttr(name);
+      }
+      /// Access attribute with implicit return type conversion
+      template <class T> T attr(const JsonChar* tag_value) const {
+        return m_element.attr<T>(tag_value);
+      }
+      /// Access attribute name (throws exception if not present)
+      const JsonChar* attr_name(const Attribute a) const {
+        return m_element.attr_name(a);
+      }
+      /// Access attribute value by the attribute  (throws exception if not present)
+      const JsonChar* attr_value(const Attribute a) const {
+        return m_element.attr_value(a);
+      }
+      /// Access the number of children of this element with a given tag name
+      size_t numChildren(const JsonChar* tag_value, bool exc = true) const {
+        return m_element.numChildren(tag_value, exc);
+      }
+      /// Retrieve a collection of all attributes of this element
+      std::vector<Attribute> attributes() const {
+        return m_element.attributes();
+      }
+      /// Access single attribute by it's name
+      Attribute getAttr(const JsonChar* name) const;
+     /// Access child by tag name. Thow an exception if required in case the child is not present
+      Handle_t child(const JsonChar* tag_value, bool except = true) const {
+        return m_element.child(tag_value, except);
+      }
+      /// Check the existence of a child with a given tag name
+      bool hasChild(const JsonChar* tag_value) const {
+        return m_element.hasChild(tag_value);
+      }
+    };
+
+
+#undef INLINE
+
+    /// Forward declarations
+    class DocumentHandler;
+
+    /// Dump partial or full JSON trees to stdout
+    void dump_tree(Handle_t elt);
+    /// Dump partial or full JSON trees
+    void dump_tree(Handle_t elt, std::ostream& os);
+    /// Dump partial or full JSON documents to stdout
+    void dump_tree(Document doc);
+    /// Dump partial or full JSON documents
+    void dump_tree(Document doc, std::ostream& os);
+
+  }       /* End namespace XML               */
+}         /* End namespace DD4hep            */
+#endif    /* DDCORE_DD4HEP_JSON_ELEMENTS_H   */
diff --git a/DDCore/include/JSON/Evaluator.h b/DDCore/include/JSON/Evaluator.h
new file mode 100644
index 000000000..665691919
--- /dev/null
+++ b/DDCore/include/JSON/Evaluator.h
@@ -0,0 +1,24 @@
+//==========================================================================
+//  AIDA Detector description implementation for LCD
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+#ifndef DD4HEP_DDCORE_JSON_EVALUATOR_H
+#define DD4HEP_DDCORE_JSON_EVALUATOR_H
+
+// Forwarding printout functionality to DD4hep
+/** Note: This is necessary to use the JSON functionality as a standalone 
+ *        utility without the need to externalize the world.
+ *
+ *  See the externalized header in doc/externalize for details.
+ */
+#include "XML/Evaluator.h"
+
+#endif   /* DD4HEP_DDCORE_JSON_EVALUATOR_H  */
diff --git a/DDCore/include/JSON/Printout.h b/DDCore/include/JSON/Printout.h
new file mode 100644
index 000000000..08dd2294e
--- /dev/null
+++ b/DDCore/include/JSON/Printout.h
@@ -0,0 +1,24 @@
+//==========================================================================
+//  AIDA Detector description implementation for LCD
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+#ifndef DD4HEP_DDCORE_JSON_PRINTOUT_H
+#define DD4HEP_DDCORE_JSON_PRINTOUT_H
+
+// Forwarding printout functionality to DD4hep
+/** Note: This is necessary to use the JSON functionality as a standalone 
+ *        utility without the need to externalize the world.
+ *
+ *  See the externalized header in doc/externalize for details.
+ */
+#include "DD4hep/Printout.h"
+
+#endif   /* DD4HEP_DDCORE_JSON_PRINTOUT_H  */
diff --git a/DDCore/include/JSON/config.h b/DDCore/include/JSON/config.h
new file mode 100644
index 000000000..aa7d5e41a
--- /dev/null
+++ b/DDCore/include/JSON/config.h
@@ -0,0 +1,35 @@
+//==========================================================================
+//  AIDA Detector description implementation for LCD
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+#ifndef DD4HEP_DDCORE_JSON_CONFIG_H
+#define DD4HEP_DDCORE_JSON_CONFIG_H
+
+#define DD4HEP_USE_BOOST_JSON 1
+
+#include <boost/property_tree/json_parser.hpp>
+#include <boost/property_tree/ptree.hpp>
+
+/// Namespace for the AIDA detector description toolkit
+namespace DD4hep {
+
+  /// Namespace for the AIDA detector description toolkit supporting JSON utilities
+  namespace JSON {
+
+    typedef char JsonChar;
+    typedef boost::property_tree::ptree             ptree;
+    typedef boost::property_tree::ptree             JsonDocument;
+    typedef boost::property_tree::ptree::value_type JsonAttr;
+    typedef boost::property_tree::ptree::value_type JsonElement;
+  }       /* End namespace JSON              */
+}         /* End namespace DD4hep            */
+
+#endif   /* DD4HEP_DDCORE_JSON_CONFIG_H  */
diff --git a/DDCore/src/JSON/Elements.cpp b/DDCore/src/JSON/Elements.cpp
new file mode 100644
index 000000000..f3617d273
--- /dev/null
+++ b/DDCore/src/JSON/Elements.cpp
@@ -0,0 +1,502 @@
+//==========================================================================
+//  AIDA Detector description implementation for LCD
+//--------------------------------------------------------------------------
+// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
+// All rights reserved.
+//
+// For the licensing terms see $DD4hepINSTALL/LICENSE.
+// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
+//
+// Author     : M.Frank
+//
+//==========================================================================
+
+// Framework include files
+#include "JSON/Printout.h"
+#include "JSON/Evaluator.h"
+#include "JSON/Elements.h"
+//#include "XML/XMLTags.h"
+
+// C/C++ include files
+#include <iostream>
+#include <stdexcept>
+#include <cstdio>
+#include <map>
+
+using namespace std;
+using namespace DD4hep::JSON;
+static const size_t INVALID_NODE = ~0U;
+
+// Forward declarations
+namespace DD4hep {
+  XmlTools::Evaluator& evaluator();
+}
+// Static storage
+namespace {
+  XmlTools::Evaluator& eval(DD4hep::evaluator());
+  string _checkEnviron(const string& env)  {
+    string r = getEnviron(env);
+    return r.empty() ? env : r;
+  }
+}
+
+namespace {
+
+  JsonElement* node_first(JsonElement* e, const JsonChar* tag) {
+    if ( e )  {
+      string t(tag);
+      if ( t == "*" )  {
+        auto i = e->second.begin();
+        return i != e->second.end() ? &(*i) : 0;
+      }
+      auto i = e->second.find(t);
+      return i != e->second.not_found() ? &(*i) : 0;
+    }
+    return 0;
+  }
+  size_t node_count(JsonElement* e, const string& t) {
+    return e ? (t=="*" ? e->second.size() : e->second.count(t)) : 0;
+  }
+}
+
+namespace {
+  Attribute attribute_node(JsonElement* n, const JsonChar* t)  {
+    auto i = n->second.find(t);
+    return i != n->second.not_found() ? &(*i) : 0;
+  }
+  const JsonChar* attribute_value(Attribute a) {
+    return a->second.get_value<std::string>().c_str();
+  }
+}
+
+string DD4hep::JSON::_toString(Attribute attr) {
+  if (attr)
+    return _toString(attribute_value(attr));
+  return "";
+}
+
+template <typename T> static inline string __to_string(T value, const char* fmt) {
+  char text[128];
+  ::snprintf(text, sizeof(text), fmt, value);
+  return text;
+}
+
+/// Do-nothing version. Present for completeness and argument interchangeability
+string DD4hep::JSON::_toString(const char* s) {
+  if ( !s || *s == 0 ) return "";
+  else if ( !(*s == '$' && *(s+1) == '{') ) return s;
+  return _checkEnviron(s);
+}
+
+/// Do-nothing version. Present for completeness and argument interchangeability
+string DD4hep::JSON::_toString(const string& s) {
+  if ( s.length() < 3 || s[0] != '$' ) return s;
+  else if ( !(s[0] == '$' && s[1] == '{') ) return s;
+  return _checkEnviron(s);
+}
+
+/// Format unsigned long integer to string with arbitrary format
+string DD4hep::JSON::_toString(unsigned long v, const char* fmt) {
+  return __to_string(v, fmt);
+}
+
+/// Format unsigned integer (32 bits) to string with arbitrary format
+string DD4hep::JSON::_toString(unsigned int v, const char* fmt) {
+  return __to_string(v, fmt);
+}
+
+/// Format signed integer (32 bits) to string with arbitrary format
+string DD4hep::JSON::_toString(int v, const char* fmt) {
+  return __to_string(v, fmt);
+}
+
+/// Format signed long integer to string with arbitrary format
+string DD4hep::JSON::_toString(long v, const char* fmt)   {
+  return __to_string(v, fmt);
+}
+
+/// Format single procision float number (32 bits) to string with arbitrary format
+string DD4hep::JSON::_toString(float v, const char* fmt) {
+  return __to_string(v, fmt);
+}
+
+/// Format double procision float number (64 bits) to string with arbitrary format
+string DD4hep::JSON::_toString(double v, const char* fmt) {
+  return __to_string(v, fmt);
+}
+
+/// Format pointer to string with arbitrary format
+string DD4hep::JSON::_ptrToString(const void* v, const char* fmt) {
+  return __to_string(v, fmt);
+}
+
+long DD4hep::JSON::_toLong(const JsonChar* value) {
+  if (value) {
+    string s = _toString(value);
+    size_t idx = s.find("(int)");
+    if (idx != string::npos)
+      s.erase(idx, 5);
+    idx = s.find("(long)");
+    if (idx != string::npos)
+      s.erase(idx, 6);
+    while (s[0] == ' ')
+      s.erase(0, 1);
+    double result = eval.evaluate(s.c_str());
+    if (eval.status() != XmlTools::Evaluator::OK) {
+      cerr << s << ": ";
+      eval.print_error();
+      throw runtime_error("DD4hep: Severe error during expression evaluation of " + s);
+    }
+    return (long) result;
+  }
+  return -1;
+}
+
+int DD4hep::JSON::_toInt(const JsonChar* value) {
+  if (value) {
+    string s = _toString(value);
+    size_t idx = s.find("(int)");
+    if (idx != string::npos)
+      s.erase(idx, 5);
+    while (s[0] == ' ')
+      s.erase(0, 1);
+    double result = eval.evaluate(s.c_str());
+    if (eval.status() != XmlTools::Evaluator::OK) {
+      cerr << s << ": ";
+      eval.print_error();
+      throw runtime_error("DD4hep: Severe error during expression evaluation of " + s);
+    }
+    return (int) result;
+  }
+  return -1;
+}
+
+bool DD4hep::JSON::_toBool(const JsonChar* value) {
+  if (value) {
+    string s = _toString(value);
+    return s == "true";
+  }
+  return false;
+}
+
+float DD4hep::JSON::_toFloat(const JsonChar* value) {
+  if (value) {
+    string s = _toString(value);
+    double result = eval.evaluate(s.c_str());
+
+    if (eval.status() != XmlTools::Evaluator::OK) {
+      cerr << s << ": ";
+      eval.print_error();
+      throw runtime_error("DD4hep: Severe error during expression evaluation of " + s);
+    }
+    return (float) result;
+  }
+  return 0.0;
+}
+
+double DD4hep::JSON::_toDouble(const JsonChar* value) {
+  if (value) {
+    string s = _toString(value);
+    double result = eval.evaluate(s.c_str());
+    if (eval.status() != XmlTools::Evaluator::OK) {
+      cerr << s << ": ";
+      eval.print_error();
+      throw runtime_error("DD4hep: Severe error during expression evaluation of " + s);
+    }
+    return result;
+  }
+  return 0.0;
+}
+
+void DD4hep::JSON::_toDictionary(const JsonChar* name, const JsonChar* value) {
+  string n = _toString(name).c_str(), v = _toString(value);
+  size_t idx = v.find("(int)");
+  if (idx != string::npos)
+    v.erase(idx, 5);
+  while (v[0] == ' ')
+    v.erase(0, 1);
+  double result = eval.evaluate(v.c_str());
+  if (eval.status() != XmlTools::Evaluator::OK) {
+    cerr << v << ": ";
+    eval.print_error();
+    throw runtime_error("DD4hep: Severe error during expression evaluation of " + v);
+  }
+  eval.setVariable(n.c_str(), result);
+}
+
+template <typename T>
+void DD4hep::JSON::_toDictionary(const JsonChar* name, T value)   {
+  string item = _toString(value);
+  _toDictionary(name, item.c_str());
+}
+
+template void DD4hep::JSON::_toDictionary(const JsonChar* name, const string& value);
+template void DD4hep::JSON::_toDictionary(const JsonChar* name, unsigned long value);
+template void DD4hep::JSON::_toDictionary(const JsonChar* name, unsigned int value);
+template void DD4hep::JSON::_toDictionary(const JsonChar* name, unsigned short value);
+template void DD4hep::JSON::_toDictionary(const JsonChar* name, int value);
+template void DD4hep::JSON::_toDictionary(const JsonChar* name, long value);
+template void DD4hep::JSON::_toDictionary(const JsonChar* name, short value);
+template void DD4hep::JSON::_toDictionary(const JsonChar* name, float value);
+template void DD4hep::JSON::_toDictionary(const JsonChar* name, double value);
+
+/// Evaluate string constant using environment stored in the evaluator
+string DD4hep::JSON::getEnviron(const string& env)   {
+  size_t id1 = env.find("${");
+  size_t id2 = env.rfind("}");
+  if ( id1 == string::npos || id2 == string::npos )   {
+    return "";
+  }
+  else  {
+    string v = env.substr(0,id2+1);
+    const char* ret = eval.getEnviron(v.c_str());
+    if (eval.status() != XmlTools::Evaluator::OK) {
+      cerr << env << ": ";
+      eval.print_error();
+      throw runtime_error("DD4hep: Severe error during environment lookup of " + env);
+    }
+    v = env.substr(0,id1);
+    v += ret;
+    v += env.substr(id2+1);
+    return v;
+  }
+}
+
+/// Copy constructor
+NodeList::NodeList(const NodeList& copy)
+  : m_tag(copy.m_tag), m_node(copy.m_node)
+{
+  reset();
+}
+
+/// Initializing constructor
+NodeList::NodeList(JsonElement* node, const string& tag_value)
+  : m_tag(tag_value), m_node(node)
+{
+  reset();
+}
+
+/// Default destructor
+NodeList::~NodeList() {
+}
+
+/// Reset the nodelist
+JsonElement* NodeList::reset() {
+  if ( m_tag == "*" )
+    m_ptr = make_pair(m_node->second.ordered_begin(), m_node->second.not_found());
+  else
+    m_ptr = m_node->second.equal_range(m_tag);
+  if ( m_ptr.first != m_ptr.second )
+    return &(*m_ptr.first);
+  return 0;
+}
+
+/// Advance to next element
+JsonElement* NodeList::next() const {
+  if ( m_ptr.first != m_ptr.second )  {
+    m_ptr.first = ++m_ptr.first;
+    if ( m_ptr.first != m_ptr.second ) return &(*m_ptr.first);
+  }
+  return 0;
+}
+
+/// Go back to previous element
+JsonElement* NodeList::previous() const {
+  if ( m_ptr.first != m_ptr.second )  {
+    m_ptr.first = --m_ptr.first;
+    if ( m_ptr.first != m_ptr.second ) return &(*m_ptr.first);
+  }
+  return 0;
+}
+
+/// Assignment operator
+NodeList& NodeList::operator=(const NodeList& l) {
+  if ( this != &l ) {
+    m_tag  = l.m_tag;
+    m_node = l.m_node;
+    reset();
+  }
+  return *this;
+}
+
+/// Unicode text access to the element's tag. This must be wrong ....
+const JsonChar* Handle_t::rawTag() const {
+  return (*m_node).first.c_str();
+}
+
+/// Unicode text access to the element's text
+const JsonChar* Handle_t::rawText() const {
+  return (*m_node).second.get_value<string>().c_str();
+}
+
+/// Unicode text access to the element's value
+const JsonChar* Handle_t::rawValue() const {
+  return (*m_node).second.get_value<string>().c_str();
+}
+
+/// Access attribute pointer by the attribute's unicode name (no exception thrown if not present)
+Attribute Handle_t::attr_nothrow(const JsonChar* tag_value) const {
+  return attribute_node(m_node, tag_value);
+}
+
+/// Check for the existence of a named attribute
+bool Handle_t::hasAttr(const JsonChar* tag_value) const {
+  return m_node && 0 != node_first(m_node, tag_value);
+}
+
+/// Retrieve a collection of all attributes of this DOM element
+vector<Attribute> Handle_t::attributes() const {
+  vector < Attribute > attrs;
+  if (m_node) {
+    for(ptree::iterator i=m_node->second.begin(); i!=m_node->second.end(); ++i)  {
+      Attribute a = &(*i);
+      attrs.push_back(a);
+    }
+  }
+  return attrs;
+}
+
+size_t Handle_t::numChildren(const JsonChar* t, bool throw_exception) const {
+  size_t n = node_count(m_node, t);
+  if (n == INVALID_NODE && !throw_exception)
+    return 0;
+  else if (n != INVALID_NODE)
+    return n;
+  string msg = "Handle_t::numChildren: ";
+  if (m_node)
+    msg += "Element [" + tag() + "] has no children of type '" + _toString(t) + "'";
+  else
+    msg += "Element [INVALID] has no children of type '" + _toString(t) + "'";
+  throw runtime_error(msg);
+}
+
+/// Remove a single child node identified by it's handle from the tree of the element
+Handle_t Handle_t::child(const JsonChar* t, bool throw_exception) const {
+  Elt_t e = node_first(m_node, t);
+  if (e || !throw_exception)
+    return e;
+  string msg = "Handle_t::child: ";
+  if (m_node)
+    msg += "Element [" + tag() + "] has no child of type '" + _toString(t) + "'";
+  else
+    msg += "Element [INVALID]. Cannot remove child of type: '" + _toString(t) + "'";
+  throw runtime_error(msg);
+}
+
+NodeList Handle_t::children(const JsonChar* tag_value) const {
+  return NodeList(m_node, tag_value);
+}
+
+bool Handle_t::hasChild(const JsonChar* tag_value) const {
+  return node_first(m_node, tag_value) != 0;
+}
+
+/// Access attribute pointer by the attribute's unicode name (throws exception if not present)
+Attribute Handle_t::attr_ptr(const JsonChar* t) const {
+  Attribute a = attribute_node(m_node, t);
+  if (0 != a)
+    return a;
+  string msg = "Handle_t::attr_ptr: ";
+  if (m_node)
+    msg += "Element [" + tag() + "] has no attribute of type '" + _toString(t) + "'";
+  else
+    msg += "Element [INVALID] has no attribute of type '" + _toString(t) + "'";
+  throw runtime_error(msg);
+}
+
+/// Access attribute name (throws exception if not present)
+const JsonChar* Handle_t::attr_name(const Attribute a) const {
+  if (a) {
+    return (*a).first.c_str();
+  }
+  throw runtime_error("Attempt to access invalid XML attribute object!");
+}
+
+/// Access attribute value by the attribute's unicode name (throws exception if not present)
+const JsonChar* Handle_t::attr_value(const JsonChar* attr_tag) const {
+  return attribute_value(attr_ptr(attr_tag));
+}
+
+/// Access attribute value by the attribute  (throws exception if not present)
+const JsonChar* Handle_t::attr_value(const Attribute attr_val) const {
+  return attribute_value(attr_val);
+}
+
+/// Access attribute value by the attribute's unicode name (no exception thrown if not present)
+const JsonChar* Handle_t::attr_value_nothrow(const JsonChar* attr_tag) const {
+  Attribute a = attr_nothrow(attr_tag);
+  return a ? attribute_value(a) : 0;
+}
+
+/// Assign new document. Old document is dropped.
+DocumentHolder& DocumentHolder::assign(DOC d)   {
+  if (m_doc)   {
+    printout(DEBUG,"DocumentHolder","+++ Release DOM document....");
+    delete m_doc;
+  }
+  m_doc = d;
+  return *this;
+}
+
+/// Standard destructor - releases the document
+DocumentHolder::~DocumentHolder() {
+  assign(0);
+}
+
+Attribute Element::getAttr(const JsonChar* name) const {
+  return m_element ? attribute_node(m_element, name) : 0;
+}
+
+Collection_t::Collection_t(Handle_t element, const char* tag_value)
+  : m_children(element, tag_value) {
+  m_node = m_children.reset();
+}
+
+/// Constructor over XmlElements in a node list
+Collection_t::Collection_t(NodeList node_list)
+  : m_children(node_list) {
+  m_node = m_children.reset();
+}
+
+/// Reset the collection object to restart the iteration
+Collection_t& Collection_t::reset() {
+  m_node = m_children.reset();
+  return *this;
+}
+
+/// Access the collection size. Avoid this call -- sloooow!
+size_t Collection_t::size() const {
+  return Handle_t(m_children.m_node).numChildren(m_children.m_tag.c_str(), false);
+}
+
+/// Helper function to throw an exception
+void Collection_t::throw_loop_exception(const exception& e) const {
+  if (m_node) {
+    throw runtime_error(string(e.what()) + "\n" + "DD4hep: Error interpreting XML nodes of type <" + tag() + "/>");
+  }
+  throw runtime_error(string(e.what()) + "\n" + "DD4hep: Error interpreting collections XML nodes.");
+}
+
+void Collection_t::operator++() const {
+  while (m_node) {
+    m_node = m_children.next();
+    if (m_node && m_node->second.size() > 0 )
+      return;
+  }
+}
+
+void Collection_t::operator--() const {
+  while (m_node) {
+    m_node = m_children.previous();
+    if (m_node && m_node->second.size() > 0 )
+      return;
+  }
+}
+
+void Collection_t::operator++(int) const {
+  ++(*this);
+}
+
+void Collection_t::operator--(int) const {
+  --(*this);
+}
-- 
GitLab