TOBI Interface A  0.1
/home/breidi/Dropbox/libtia/src/tia/newtia/tia_meta_info_parse_and_build_functions.cpp
00001 /*
00002     This file is part of the TOBI Interface A (TiA) library.
00003 
00004     Commercial Usage
00005     Licensees holding valid Graz University of Technology Commercial
00006     licenses may use this file in accordance with the Graz University
00007     of Technology Commercial License Agreement provided with the
00008     Software or, alternatively, in accordance with the terms contained in
00009     a written agreement between you and Graz University of Technology.
00010 
00011     --------------------------------------------------
00012 
00013     GNU Lesser General Public License Usage
00014     Alternatively, this file may be used under the terms of the GNU Lesser
00015     General Public License version 3.0 as published by the Free Software
00016     Foundation and appearing in the file lgpl.txt included in the
00017     packaging of this file.  Please review the following information to
00018     ensure the GNU General Public License version 3.0 requirements will be
00019     met: http://www.gnu.org/copyleft/lgpl.html.
00020 
00021     In case of GNU Lesser General Public License Usage ,the TiA library
00022     is distributed in the hope that it will be useful,
00023     but WITHOUT ANY WARRANTY; without even the implied warranty of
00024     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00025     GNU General Public License for more details.
00026 
00027     You should have received a copy of the GNU Lesser General Public License
00028     along with the TiA library. If not, see <http://www.gnu.org/licenses/>.
00029 
00030     Copyright 2010 Graz University of Technology
00031     Contact: TiA@tobi-project.org
00032 */
00033 
00034 #include "tia-private/newtia/tia_meta_info_parse_and_build_functions.h"
00035 #include "tia-private/newtia/tia_exceptions.h"
00036 
00037 #include "tia-private/newtia/string_utils.h"
00038 #include <rapidxml/rapidxml.hpp>
00039 #include <rapidxml/rapidxml_print.hpp>
00040 
00041 #include <sstream>
00042 #include <map>
00043 #include <set>
00044 
00045 using std::string;
00046 using std::map;
00047 using std::set;
00048 
00049 namespace tia
00050 {
00051 
00052 namespace XML_TAGS
00053 {
00054     std::string const TIA_META_INFO = "tiaMetaInfo";
00055     std::string const TIA_META_INFO_VERSION = "version";
00056     std::string const TIA_META_INFO_CURRENT_VERSION = "1.0";
00057 
00058     std::string const SUBJECT = "subject";
00059     std::string const SUBJECT_ID = "id";
00060     std::string const SUBJECT_FIRSTNAME = "firstName";
00061     std::string const SUBJECT_SURNAME = "surname";
00062 
00063     std::string const MASTER_SIGNAL = "masterSignal";
00064     std::string const SIGNAL = "signal";
00065     std::string const SIGNAL_TYPE = "type";
00066     std::string const SIGNAL_SAMPLINGRATE = "samplingRate";
00067     std::string const SIGNAL_NUMCHANNELS = "numChannels";
00068     std::string const SIGNAL_BLOCKSIZE = "blockSize";
00069     string const SIGNAL_REQUIRED_ATTRIBUTES_ARRAY[] = {SIGNAL_TYPE, SIGNAL_SAMPLINGRATE, SIGNAL_BLOCKSIZE, SIGNAL_NUMCHANNELS};
00070     set<string> const SIGNAL_REQUIRED_ATTRIBUTES (SIGNAL_REQUIRED_ATTRIBUTES_ARRAY, SIGNAL_REQUIRED_ATTRIBUTES_ARRAY + 4);
00071 
00072     std::string const CHANNEL = "channel";
00073     std::string const CHANNEL_NR = "nr";
00074     std::string const CHANNEL_LABEL = "label";
00075     string const CHANNEL_REQUIRED_ATTRIBUTES_ARRAY[] = {CHANNEL_NR, CHANNEL_LABEL};
00076     set<string> const CHANNEL_REQUIRED_ATTRIBUTES (CHANNEL_REQUIRED_ATTRIBUTES_ARRAY, CHANNEL_REQUIRED_ATTRIBUTES_ARRAY + 2);
00077 }
00078 
00079 //-----------------------------------------------------------------------------
00080 void addAttribute (rapidxml::xml_document<>* doc, rapidxml::xml_node<>* node, std::string const& attribute_name, std::string const& attribute_value);
00081 void addAttribute (rapidxml::xml_document<>* doc, rapidxml::xml_node<>* node, std::string const& attribute_name, unsigned attribute_value);
00082 map<string, string> getAttributes (rapidxml::xml_node<>* node);
00083 map<string, string> getAttributes (rapidxml::xml_node<>* node, set<string> required_attributes);
00084 
00085 //-----------------------------------------------------------------------------
00086 SSConfig parseTiAMetaInfoFromXMLString (std::string const& tia_meta_info_xml_string)
00087 {
00088     SSConfig tia_meta_info;
00089     rapidxml::xml_document<> xml_doc;
00090     try
00091     {
00092         xml_doc.parse<rapidxml::parse_non_destructive | rapidxml::parse_validate_closing_tags> ((char*)tia_meta_info_xml_string.c_str ());
00093     }
00094     catch (rapidxml::parse_error &error)
00095     {
00096         throw TiAException (string (error.what()));
00097     }
00098 
00099     rapidxml::xml_node<>* tia_metainfo_node = xml_doc.first_node ();
00100     if (tia_metainfo_node->next_sibling ())
00101         throw TiAException ("Parsing TiAMetaInfo String: Too many first level nodes.");
00102 
00103     // parse subject
00104     rapidxml::xml_node<>* subject_node = tia_metainfo_node->first_node (XML_TAGS::SUBJECT.c_str());
00105     if (subject_node)
00106     {
00107         std::map<string, string> attributes = getAttributes (subject_node);
00108         if (attributes.count (XML_TAGS::SUBJECT_ID))
00109             tia_meta_info.subject_info.setId (attributes.at(XML_TAGS::SUBJECT_ID));
00110         if (attributes.count (XML_TAGS::SUBJECT_FIRSTNAME))
00111             tia_meta_info.subject_info.setFirstName (attributes.at(XML_TAGS::SUBJECT_FIRSTNAME));
00112         if (attributes.count (XML_TAGS::SUBJECT_SURNAME))
00113             tia_meta_info.subject_info.setSurname (attributes.at(XML_TAGS::SUBJECT_SURNAME));
00114     }
00115 
00116     // parse master signal info
00117     rapidxml::xml_node<>* master_signal_node = 0;
00118     master_signal_node = tia_metainfo_node->first_node (XML_TAGS::MASTER_SIGNAL.c_str());
00119     if (master_signal_node)
00120     {
00121         std::map<string, string> attributes = getAttributes (master_signal_node);
00122         if (attributes.count (XML_TAGS::SIGNAL_SAMPLINGRATE))
00123             tia_meta_info.signal_info.setMasterSamplingRate (toUnsigned (attributes.at(XML_TAGS::SIGNAL_SAMPLINGRATE)));
00124         if (attributes.count (XML_TAGS::SIGNAL_BLOCKSIZE))
00125             tia_meta_info.signal_info.setMasterBlockSize (toUnsigned (attributes.at(XML_TAGS::SIGNAL_BLOCKSIZE)));
00126     }
00127 
00128 
00129     // parse signals
00130     rapidxml::xml_node<>* signal_node = 0;
00131     signal_node = tia_metainfo_node->first_node (XML_TAGS::SIGNAL.c_str());
00132     SignalInfo::SignalMap& signal_map = tia_meta_info.signal_info.signals ();
00133     while (signal_node)
00134     {
00135         Signal signal;
00136         map<string, string> signal_attributes = getAttributes (signal_node, XML_TAGS::SIGNAL_REQUIRED_ATTRIBUTES);
00137         signal.setType (signal_attributes[XML_TAGS::SIGNAL_TYPE]);
00138         signal.setSamplingRate (toUnsigned (signal_attributes[XML_TAGS::SIGNAL_SAMPLINGRATE]));
00139         signal.setBlockSize (toUnsigned (signal_attributes[XML_TAGS::SIGNAL_BLOCKSIZE]));
00140 
00141         unsigned const num_channels = toUnsigned (signal_attributes[XML_TAGS::SIGNAL_NUMCHANNELS]);
00142 
00143         // parse channels
00144         std::vector<Channel>& channel_vector = signal.channels();
00145         for (unsigned channel_nr = 0; channel_nr < num_channels; channel_nr++)
00146         {
00147             Channel channel;
00148             channel.setId (toString (channel_nr));
00149             channel_vector.push_back (channel);
00150         }
00151 
00152         rapidxml::xml_node<>* channel_node = signal_node->first_node (XML_TAGS::CHANNEL.c_str());
00153         while (channel_node)
00154         {
00155             map<string, string> channel_attributes = getAttributes (channel_node, XML_TAGS::CHANNEL_REQUIRED_ATTRIBUTES);
00156             unsigned channel_nr = toUnsigned (channel_attributes[XML_TAGS::CHANNEL_NR]);
00157             if (channel_nr > num_channels)
00158                 throw TiAException ("Parse TiAMetaInfo: nr-attribute of channel exceeds numChannels attribute of signal!");
00159 
00160             channel_vector[channel_nr - 1].setId (channel_attributes[XML_TAGS::CHANNEL_LABEL]);
00161             channel_node = channel_node->next_sibling (XML_TAGS::CHANNEL.c_str ());
00162         }
00163 
00164         signal_map[signal_attributes[XML_TAGS::SIGNAL_TYPE]] = signal;
00165         signal_node = signal_node->next_sibling (XML_TAGS::SIGNAL.c_str ());
00166     }
00167 
00168     return tia_meta_info;
00169 }
00170 
00171 //-----------------------------------------------------------------------------
00172 std::string buildTiAMetaInfoXMLString (SSConfig const& tia_meta_info)
00173 {
00174     rapidxml::xml_document<> xml_doc;
00175 
00176     char *tia_metainfo_node_name = xml_doc.allocate_string (XML_TAGS::TIA_META_INFO.c_str ());
00177     rapidxml::xml_node<>* tia_metainfo_node = xml_doc.allocate_node (rapidxml::node_element, tia_metainfo_node_name);
00178 
00179     addAttribute (&xml_doc, tia_metainfo_node,
00180                   XML_TAGS::TIA_META_INFO_VERSION, XML_TAGS::TIA_META_INFO_CURRENT_VERSION);
00181 
00182     // subject node
00183     char *subject_node_name = xml_doc.allocate_string (XML_TAGS::SUBJECT.c_str ());
00184     rapidxml::xml_node<>* subject_node = xml_doc.allocate_node (rapidxml::node_element, subject_node_name);
00185     addAttribute (&xml_doc, subject_node, XML_TAGS::SUBJECT_ID, tia_meta_info.subject_info.id());
00186     addAttribute (&xml_doc, subject_node, XML_TAGS::SUBJECT_FIRSTNAME, tia_meta_info.subject_info.firstName());
00187     addAttribute (&xml_doc, subject_node, XML_TAGS::SUBJECT_SURNAME, tia_meta_info.subject_info.surname());
00188     // TODO: add further attributes
00189     tia_metainfo_node->append_node (subject_node);
00190 
00191 
00192     // master signal data
00193     char *master_signal_node_name = xml_doc.allocate_string (XML_TAGS::MASTER_SIGNAL.c_str ());
00194     rapidxml::xml_node<>* master_signal_node = xml_doc.allocate_node (rapidxml::node_element, master_signal_node_name);
00195     addAttribute (&xml_doc, master_signal_node, XML_TAGS::SIGNAL_SAMPLINGRATE, tia_meta_info.signal_info.masterSamplingRate());
00196     addAttribute (&xml_doc, master_signal_node, XML_TAGS::SIGNAL_BLOCKSIZE, tia_meta_info.signal_info.masterBlockSize());
00197     tia_metainfo_node->append_node (master_signal_node);
00198 
00199 
00200     // signals
00201     for (SignalInfo::SignalMap::const_iterator signal_iter = tia_meta_info.signal_info.signals().begin ();
00202          signal_iter != tia_meta_info.signal_info.signals ().end (); ++signal_iter)
00203     {
00204         char *signal_node_name = xml_doc.allocate_string (XML_TAGS::SIGNAL.c_str ());
00205         rapidxml::xml_node<>* signal_node = xml_doc.allocate_node (rapidxml::node_element, signal_node_name);
00206         addAttribute (&xml_doc, signal_node, XML_TAGS::SIGNAL_TYPE, signal_iter->second.type ());
00207         addAttribute (&xml_doc, signal_node, XML_TAGS::SIGNAL_SAMPLINGRATE, signal_iter->second.samplingRate());
00208         addAttribute (&xml_doc, signal_node, XML_TAGS::SIGNAL_BLOCKSIZE, signal_iter->second.blockSize());
00209         addAttribute (&xml_doc, signal_node, XML_TAGS::SIGNAL_NUMCHANNELS, signal_iter->second.channels().size ());
00210 
00211         for (unsigned channel_nr = 0; channel_nr < signal_iter->second.channels().size (); channel_nr++)
00212         {
00213             char *channel_node_name = xml_doc.allocate_string (XML_TAGS::CHANNEL.c_str ());
00214             rapidxml::xml_node<>* channel_node = xml_doc.allocate_node (rapidxml::node_element, channel_node_name);
00215             addAttribute (&xml_doc, channel_node, XML_TAGS::CHANNEL_NR, channel_nr + 1);
00216             addAttribute (&xml_doc, channel_node, XML_TAGS::CHANNEL_LABEL, signal_iter->second.channels ()[channel_nr].id());
00217             signal_node->append_node (channel_node);
00218         }
00219 
00220         tia_metainfo_node->append_node (signal_node);
00221     }
00222 
00223 
00224     xml_doc.append_node (tia_metainfo_node);
00225 
00226     string xml_string;
00227     rapidxml::print (std::back_inserter (xml_string), xml_doc, 0);
00228     return xml_string;
00229 }
00230 
00231 //-----------------------------------------------------------------------------
00232 void addAttribute (rapidxml::xml_document<>* doc, rapidxml::xml_node<>* node, std::string const& attribute_name, std::string const& attribute_value)
00233 {
00234     if (attribute_value.size())
00235     {
00236         char *attribute_name_rx = doc->allocate_string (attribute_name.c_str ());
00237         char *attribute_value_rx = doc->allocate_string (attribute_value.c_str());
00238 
00239         rapidxml::xml_attribute<>* attribute = doc->allocate_attribute (attribute_name_rx, attribute_value_rx, attribute_name.size (), attribute_value.size());
00240         node->append_attribute (attribute);
00241     }
00242 }
00243 
00244 //-----------------------------------------------------------------------------
00245 void addAttribute (rapidxml::xml_document<>* doc, rapidxml::xml_node<>* node, std::string const& attribute_name, unsigned attribute_value)
00246 {
00247     std::ostringstream oss;
00248     oss << std::dec << attribute_value;
00249     addAttribute (doc, node, attribute_name, oss.str ());
00250 }
00251 
00252 
00253 //-----------------------------------------------------------------------------
00254 map<string, string> getAttributes (rapidxml::xml_node<>* node)
00255 {
00256     set<string> no_required_attributes;
00257     return getAttributes (node, no_required_attributes);
00258 }
00259 
00260 //-----------------------------------------------------------------------------
00261 map<std::string, std::string> getAttributes (rapidxml::xml_node<>* node, set<string> required_attributes)
00262 {
00263     std::map<string, string> attributes;
00264     if (!node)
00265         return attributes;
00266     rapidxml::xml_attribute<>* attribute = node->first_attribute ();
00267     while (attribute)
00268     {
00269         string key (attribute->name (), attribute->name_size ());
00270         required_attributes.erase (key);
00271         string value (attribute->value (), attribute->value_size ());
00272         attributes[key] = value;
00273         attribute = attribute->next_attribute ();
00274     }
00275 
00276     if (required_attributes.size ())
00277     {
00278         string missing_attributes;
00279         for (set<string>::const_iterator iter = required_attributes.begin (); iter != required_attributes.end (); )
00280         {
00281             missing_attributes += *iter;
00282             if (++iter != required_attributes.end ())
00283                 missing_attributes += ", ";
00284         }
00285         throw TiAException (string ("Parse TiAMetaInfo: Required attributes missing: ") + missing_attributes);
00286     }
00287     return attributes;
00288 }
00289 
00290 
00291 
00292 }
 All Data Structures Files Functions Variables Typedefs Enumerations