freXMLStreamObject.cxx

Go to the documentation of this file.
00001 /*=========================================================================
00002 
00003   Program:   F.R.E.E. - flexible registration evaluation engine
00004   Version:   v.1.0.0
00005   Date:      $Date: 2006/09/01 12:00:00 $
00006   Module:    $RCSfile: freXMLStreamObject.cxx,v $
00007   Language:  C++
00008 
00009 
00010 
00011   Copyright (c) 2007 Ralf o Floca (Department of Medical Informatics,
00012   Institute for Medical Biometry and Informatics, University of Heidelberg,
00013   Germany). All rights reserved.
00014   See FREECopyright.txt or http://www.mi.med.uni-hd.de/free/copyright.htm
00015   for details.
00016 
00017      This software is distributed WITHOUT ANY WARRANTY; without even 
00018      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
00019      PURPOSE.  See the above copyright notices for more information.
00020 
00021 =========================================================================*/
00022 #include "freXMLStreamObject.h"
00023 #include "freExceptions.h"
00024 #include "freConvert.h"
00025 
00026 #include "fstream"
00027 
00028 #include <itksys/SystemTools.hxx>
00029 
00030 namespace FREE
00031 {
00032 
00033 const std::string XMLStreamObject::cXML_Text ="";
00034 
00038 
00039 void
00040 XMLStreamObject::
00041 CB_Static_StartElement(void* parser, const char *name,
00042                        const char **pAttributes)
00043 {
00044   // Begin element handler that is registered with the XML_Parser.
00045   // This just casts the user data to an itkXMLParser and calls
00046   // StartElement.
00047   static_cast<XMLStreamObject*>(parser)->CB_StartElement(name, pAttributes);
00048 }
00049 
00050 void
00051 XMLStreamObject::
00052 CB_Static_EndElement(void* parser, const char *name)
00053 {
00054   // End element handler that is registered with the XML_Parser.  This
00055   // just casts the user data to an itkXMLParser and calls EndElement.
00056   static_cast<XMLStreamObject*>(parser)->CB_EndElement(name);
00057 }
00058 
00059 void
00060 XMLStreamObject::
00061 CB_Static_CharacterDataHandler(void* parser, const char* data,
00062                                int length)
00063 {
00064   // Character data handler that is registered with the XML_Parser.
00065   // This just casts the user data to an itkXMLParser and calls
00066   // CharacterDataHandler.
00067   static_cast<XMLStreamObject*>(parser)->CB_CharacterDataHandler(data, length);
00068 }
00069 
00070 void
00071 XMLStreamObject::
00072 LoadFromString(const std::string& rsRawData)
00073 {
00074   m_Parser = XML_ParserCreate(0);
00075   XML_SetElementHandler(m_Parser,&CB_Static_StartElement,&CB_Static_EndElement);
00076   XML_SetCharacterDataHandler(m_Parser, NULL);
00077   XML_SetUserData(m_Parser,this);
00078 
00079   Reset();
00080   ResetRequirements();
00081   ResetLoadingHelpers();
00082 
00083   m_psLoadData = &rsRawData;
00084 
00085   bool result = XML_Parse(m_Parser,m_psLoadData->c_str(),m_psLoadData->size(),true);
00086     
00087   if(!result)
00088   {
00089     std::string errorMsg(XML_ErrorString(XML_GetErrorCode(m_Parser)));
00090     std::string errorPos = Convert::ToStr(XML_GetCurrentLineNumber(m_Parser))+":"+Convert::ToStr(XML_GetCurrentColumnNumber(m_Parser));
00091     throwExceptionMacro("Expat error while parsing raw string. Error: "<<errorMsg<<"; Error position: "<<errorPos);
00092   }
00093 
00094   XML_ParserFree(m_Parser);
00095   
00096   FinalizeLoading();
00097 
00098   CheckValidLoading();
00099   
00100   ResetLoadingHelpers();
00101 };
00102 
00103 std::string XMLStreamObject::SaveToString() const
00104 {
00105   return SaveToString(0);
00106 };
00107 
00108 void
00109 XMLStreamObject::
00110 SaveToFile(const std::string& sFileName,
00111            const std::string& sXSLT,
00112            const std::string& sEncoding) const
00113 {
00114   std::ofstream file;
00115 
00116   std::ios_base::openmode iOpenFlag = std::ios_base::out | std::ios_base::trunc;
00117         file.open(sFileName.c_str(), iOpenFlag );
00118 
00119         if (!file.is_open()) throwExceptionMacro("Cannot open or create specified file to save. Filename: "<<sFileName);
00120 
00121   try
00122   {
00123     if (!sEncoding.empty())     file <<"<?xml version=\"1.0\" encoding=\""<<sEncoding<<"\"?>\n";
00124     if (!sXSLT.empty()) file <<"<?xml-stylesheet type=\"text/xsl\" href=\""<<sXSLT<<"\"?>\n";
00125     file << this->SaveToString();
00126     file.close();
00127   }
00128   catchAllNPassMacro("Unknown error occured while saving setup. Please check error log for further information.");
00129 };
00130 
00131 void
00132 XMLStreamObject::
00133 LoadFromFile(const std::string& sFileName)
00134 {
00135   std::ifstream file;
00136 
00137   std::ios_base::openmode iOpenFlag = std::ios_base::in;// | std::ios_base::binary;
00138         file.open(sFileName.c_str(), iOpenFlag );
00139 
00140         if (!file.is_open()) throwExceptionMacro("Cannot open or create specified file to load. Filename: " << sFileName);
00141 
00142   try
00143   {
00144     std::streamsize filesize = itksys::SystemTools::FileLength(sFileName.c_str());
00145     char *buffer = new char [filesize];
00146 
00147     file.read(buffer,filesize);
00148 
00149     std::streamsize gsize = file.gcount();
00150 
00151     std::string data(buffer,gsize);
00152 
00153     delete[] buffer;
00154     file.close();
00155 
00156     this->LoadFromString(data);
00157   }
00158   catchAllNPassMacro("Unknown error occured while loading setup. Please check error log for further information.");
00159 };
00160 
00161 void
00162 XMLStreamObject::
00163 Reset()
00164 {
00165   //Should be reimplimented by derived classes.
00166 };
00167 
00168 const std::string
00169 XMLStreamObject::
00170 GetXMLTag() const
00171 { return m_sXMLTag; };
00172 
00173 void
00174 XMLStreamObject::
00175 CB_StartElement(const char * name,const char **pAttributes)
00176 {
00177   if (m_iActSubElementLevel==0)
00178   {
00179     if (name == GetXMLTag())
00180     {
00181       AttributesLoadProcessing(ConvertExpatAttrToMap(pAttributes));
00182       XML_SetCharacterDataHandler(m_Parser, &CB_Static_CharacterDataHandler);
00183     }
00184                 else throwExceptionMacro("Wrong xml tag for used xml stream object class. Used Tag: " << name << ".Required Tag: " << this->GetXMLTag());
00185   }
00186   else if (m_iActSubElementLevel==1)
00187   {
00188     CommitSubElement();
00189     m_lContentStartPos = -1;
00190     m_lContentStopPos = -1;
00191     m_lElementStopPos = -1;
00192 
00193     //Now take care about the found element
00194     m_sActSubElementTag = name;
00195     m_ActSubElementAttributes = ConvertExpatAttrToMap(pAttributes);
00196     m_lElementStartPos = XML_GetCurrentByteIndex(m_Parser);
00197 
00198     //Set handle to be aware of the data beginning
00199     XML_SetCharacterDataHandler(m_Parser, &CB_Static_CharacterDataHandler);
00200   }
00201   else XML_SetCharacterDataHandler(m_Parser, NULL); //another start tag of a sub element has appeared, we don't need to wait for text data anymore
00202 
00203   m_iActSubElementLevel++;
00204 };
00205 
00206 void
00207 XMLStreamObject::
00208 CB_EndElement(const char *name)
00209 {
00210   m_iActSubElementLevel--;
00211 
00212   if (m_iActSubElementLevel==1) //reached the end tag of a top level element
00213   {
00214     m_lContentStopPos = XML_GetCurrentByteIndex(m_Parser);
00215 
00216     //Set handle to be aware of text data before the next tag
00217     XML_SetCharacterDataHandler(m_Parser, &CB_Static_CharacterDataHandler);
00218   }
00219   else if (m_iActSubElementLevel==0) //reached and of xml element
00220   {
00221     CommitSubElement();
00222   };
00223 };
00224 
00225 void
00226 XMLStreamObject::
00227 CB_CharacterDataHandler(const char *inData, int inLength)
00228 {
00229   CommitSubElement();
00230   m_lContentStartPos = XML_GetCurrentByteIndex(m_Parser);
00231   m_lContentStopPos = -1;
00232   m_lElementStopPos = -1;
00233 
00234   //we only need this callback once, to get aware of the begining pos of sub element data
00235   XML_SetCharacterDataHandler(m_Parser, NULL);
00236 };
00237 
00238 XMLStreamObject&
00239 XMLStreamObject::
00240 operator = (const XMLStreamObject& rXMLStreamObject)
00241 {
00242   m_sXMLTag = rXMLStreamObject.GetXMLTag();
00243   // all other private members are helpers of the loading process, so only valid while
00244   // loading and for this reason not needed to be copied.
00245   
00246   return *this;
00247 };
00248 
00249 XMLStreamObject::
00250 XMLStreamObject(const std::string& sXMLTag)
00251 {
00252   m_sXMLTag = sXMLTag;
00253   ResetLoadingHelpers();
00254 };
00255 
00256 XMLStreamObject::
00257 XMLStreamObject(const XMLStreamObject& rXMLStreamObject)
00258 {
00259   ResetLoadingHelpers();
00260   *this = rXMLStreamObject;
00261 };
00262 
00263 XMLStreamObject::
00264 ~XMLStreamObject()
00265 {
00266   ResetLoadingHelpers();
00267 };
00268 
00269 void
00270 XMLStreamObject::
00271 SubElementLoadProcessing(const std::string& rsXMLSubTag, const std::string& rsXMLSubElement, const std::string& rsXMLSubData)
00272 {
00273   if (rsXMLSubTag!=cXML_Text) throwExceptionMacro("Unknown xml tag, unable to load value. Incorrect Tag: " << rsXMLSubTag);
00274   //Should be reimplimented by derived classes, to create the loading behaviour for
00275   //different sub elements of this class.
00276   //Reminder: plain text data elements have a rsXMLSubTag==cXML_Text.
00277 };
00278 
00279 void
00280 XMLStreamObject::
00281 AttributesLoadProcessing(const AttributesType& rAttributes)
00282 {
00283   //Should be reimplimented by derived classes, to adjust their loading behaviour
00284   //depending on the attributes of this class.
00285 };
00286 
00287 void
00288 XMLStreamObject::
00289 SaveAttributes(AttributesSaveListType& rAttributes) const
00290 {
00291   //Should be reimplimented by derived classes, to adjust their xml attribute saving behaviour.
00292 };
00293 
00294 std::string
00295 XMLStreamObject::
00296 SaveData(const unsigned int& iDepth, bool& bHasSubElements) const
00297 {
00298         bHasSubElements = false;
00299   return "";
00300   //Should be reimplimented by derived classes, to adjust their xml data saving behaviour.
00301 };
00302 
00303 std::string
00304 XMLStreamObject::
00305 SaveToString(const unsigned int& iDepth) const
00306 {
00307   AttributesSaveListType attrs;
00308   std::string sAttrs = "";
00309 
00310   try
00311   {
00312     SaveAttributes(attrs);
00313   }
00314   catchAllNPassMacro("Unkown error when saving attributes of tag. Tag: "+this->GetXMLTag());
00315   
00316         bool bHasSubElements = true;
00317 
00318   try
00319   {
00320     sAttrs = ConvertAttributesToString(attrs);
00321   }
00322   catchAllNPassMacro("Unkown error when converting attribute structure into save string. Tag: "+this->GetXMLTag());
00323 
00324   std::string sElement = "";
00325   try
00326   {
00327     sElement = SaveData(iDepth, bHasSubElements);
00328   }
00329   catchAllNPassMacro("Unkown error when converting element data into save string. Tag: "+this->GetXMLTag());
00330   
00331   std::string sResult = "<";
00332     
00333   try
00334   {
00335     sResult += GetXMLTag();
00336   }
00337   catchAllNPassMacro("Unkown error when adding XML Tag. Tag: "+this->GetXMLTag());
00338         
00339   try
00340   {
00341     AddIndentation(sResult, iDepth);
00342   }
00343   catchAllNPassMacro("Unkown error when adding indentation. Tag: "+this->GetXMLTag());
00344 
00345   std::string sEndTag = "";
00346 
00347   try
00348   {
00349     sEndTag = "</"+GetXMLTag()+">";
00350     if (bHasSubElements)
00351           {
00352                   AddIndentation(sEndTag, iDepth);
00353                   sEndTag = "\n"+sEndTag;
00354           }
00355   }
00356   catchAllNPassMacro("Unkown error when formatting end tag. Tag: "+this->GetXMLTag());
00357 
00358   try
00359   {
00360     if (sAttrs.size()) sResult += " "+sAttrs;
00361   }
00362   catchAllNPassMacro("Unkown error when adding attr string. Tag: "+this->GetXMLTag());
00363 
00364   try
00365   {
00366     if (sElement.size()) sResult += ">"+sElement+sEndTag;
00367           else sResult += " />";
00368   }
00369   catchAllNPassMacro("Unkown error when adding element string. Tag: "+this->GetXMLTag());
00370 
00371   try
00372   {
00373     return sResult;
00374   }
00375   catchAllNPassMacro("Unkown error when returning result. Tag: "+this->GetXMLTag());
00376 
00377   return "";
00378 };
00379 
00380 std::string
00381 XMLStreamObject::
00382 CreateSimpleElement(const std::string& sTag, const std::string& sValue)
00383 {
00384   std::string sResult = "<"+sTag+">"+sValue+"</"+sTag+">";
00385         return sResult;
00386 };
00387 
00388 void
00389 XMLStreamObject::
00390 AddSubElement(std::string& sData, const std::string& sTag, const std::string& sValue, const unsigned int& iParentalDepth)
00391 {
00392   try
00393   {
00394     std::string sResult = CreateSimpleElement(sTag,sValue);
00395     AddIndentation(sResult,iParentalDepth+1);
00396     sData += '\n'+sResult;
00397   }
00398   catchAllNPassStaticMacro("Unknown error while adding subelement to save string. Subelement tag: "+sTag+"; value: "+sValue+"; parental depth: "+Convert::ToStr(iParentalDepth));
00399 };
00400 
00401 void
00402 XMLStreamObject::
00403 AddSubElement(std::string& sData, const std::string& sTag, const std::string& sValue, const AttributesType& rAttributes, const unsigned int& iParentalDepth)
00404 {
00405   try
00406   {
00407     std::string sAttr = "";
00408     for (AttributesType::const_iterator pos = rAttributes.begin(); pos != rAttributes.end(); pos++)
00409     {
00410       sAttr += " "+pos->first+"=\""+pos->second+"\"";
00411     }
00412     std::string sResult = "<"+sTag+sAttr+">"+sValue+"</"+sTag+">";
00413     AddIndentation(sResult,iParentalDepth+1);
00414     sData += '\n'+sResult;
00415   }
00416   catchAllNPassStaticMacro("Unknown error while adding subelement to save string. Subelement tag: "+sTag+"; value: "+sValue+"; parental depth: "+Convert::ToStr(iParentalDepth));
00417 };
00418 
00419 void
00420 XMLStreamObject::
00421 AddSubElement(std::string& sData, const XMLStreamObject* pSubElement, const unsigned int& iParentalDepth)
00422 {
00423   std::string sTag = "NULL sub element";
00424   if (pSubElement)
00425   {
00426     sTag = pSubElement->GetXMLTag();
00427     std::string sResult = "";
00428     try
00429     {
00430       sResult = pSubElement->SaveToString(iParentalDepth+1);
00431     }
00432     catchAllNPassStaticMacro("Unknown error while generating subelement save string. Subelement tag: "+sTag+"; parental depth: "+Convert::ToStr(iParentalDepth));
00433     try
00434     {
00435       sData += "\n"+sResult;
00436     }
00437     catchAllNPassStaticMacro("Unknown error while adding subelement save string. Subelement tag: "+sTag+"; parental depth: "+Convert::ToStr(iParentalDepth)+"; sub element string: "+sResult);
00438   }
00439   else
00440   {
00441                 std::string sLocation;
00442                 GetStaticLocationMacro( sLocation );
00443     FREE::LogException("Warning", "Passed sub element was NULL.",sLocation);
00444   }
00445 };
00446 
00447 void
00448 XMLStreamObject::
00449 AddSubElement(std::string& sData, const std::string& sSubElement, const unsigned int& iParentalDepth)
00450 {
00451   try
00452   {
00453     std::string sResult = sSubElement;
00454     AddIndentation(sResult,iParentalDepth+1);
00455     sData += '\n'+sResult;
00456   }
00457   catchAllNPassStaticMacro("Unknown error while adding subelement to save string. parental depth: "+Convert::ToStr(iParentalDepth)+"; subelement save string: "+sSubElement);
00458 };
00459 
00460 void
00461 XMLStreamObject::
00462 AddIndentation(std::string& sData, const unsigned int& iDepth)
00463 {
00464   std::string sIndent;
00465   for (unsigned int i=0; i<iDepth; i++) sIndent+="   ";
00466   sData = sIndent+sData;
00467 };
00468 
00469 bool
00470 XMLStreamObject::
00471 CheckValidLoading() const
00472 {
00473   if (m_NeededSubElements.size()>0)
00474   {
00475     std::string sMissing;
00476     STLStringVector::const_iterator pos;
00477 
00478     for (pos = m_NeededSubElements.begin(); pos != m_NeededSubElements.end(); pos++)
00479     {
00480       sMissing += *pos + " ";
00481     };
00482     throwExceptionMacro("Loading of object was invalid, because required sub tags where missing. Please check xml file with schema definition. Missing tags: " << sMissing);
00483   }
00484   return true;
00485   //Should be reimplimented by derived classes, to adjust the checking.
00486 };
00487 
00488 void
00489 XMLStreamObject::
00490 SetNeededSubElements()
00491 {
00492   //Should be reimplimented by derived classes, to set needed elements for loading validation.
00493   //Use AddNeededSubElement() to add an element
00494   //If this function is called by XMLStreamObject, the list of needed elements has been cleared.
00495 };
00496 
00497 void
00498 XMLStreamObject::
00499 AddNeededSubElement(const std::string& sSubElementTag)
00500 {
00501   m_NeededSubElements.push_back(sSubElementTag);
00502 };
00503 
00504 void
00505 XMLStreamObject::
00506 NotifyFoundSubElement(const std::string& sSubElementTag)
00507 {
00508   STLStringVector::iterator pos;
00509 
00510   for (pos = m_NeededSubElements.begin(); pos != m_NeededSubElements.end(); pos++)
00511   {
00512     if ((*pos)==sSubElementTag)
00513     {
00514       m_NeededSubElements.erase(pos);
00515       return;
00516     }
00517   };
00518 };
00519 
00520 void
00521 XMLStreamObject::
00522 ResetRequirements()
00523 {
00524   m_NeededSubElements.clear();
00525   SetNeededSubElements();
00526 };
00527 
00528 void
00529 XMLStreamObject::
00530 ResetLoadingHelpers()
00531 {
00532   m_iActSubElementLevel = 0;
00533   m_sActSubElementTag.erase();
00534   m_ActSubElementAttributes.clear();
00535   m_psLoadData = NULL;
00536   m_lElementStartPos = -1;
00537   m_lElementStopPos = -1;
00538   m_lContentStartPos = -1;
00539   m_lContentStopPos = -1;
00540 };
00541 
00542 XMLStreamObject::AttributesType
00543 XMLStreamObject::
00544 ConvertExpatAttrToMap(const char** pAttributes)
00545 {
00546   AttributesType attrs;
00547   
00548   const char** pActAttr = pAttributes;
00549 
00550   while (*pActAttr)
00551   {
00552     std::string sKey = *pActAttr;
00553     pActAttr++;
00554     std::string sValue = *pActAttr;
00555     pActAttr++;
00556     attrs.insert(AttributeType(sKey,sValue));
00557   };
00558 
00559   return attrs;
00560 };
00561 
00562 std::string
00563 XMLStreamObject::
00564 ExtractSubElementXmlString()
00565 {
00566   if (m_lElementStartPos==-1) return "";
00567   
00568   if (m_lElementStartPos>m_lElementStopPos) return "";
00569 
00570   return m_psLoadData->substr(m_lElementStartPos,m_lElementStopPos-m_lElementStartPos);
00571 };
00572 
00573 std::string
00574 XMLStreamObject::
00575 ExtractSubElementContentString()
00576 {
00577   if (m_lContentStartPos==-1) return "";
00578   
00579   if (m_lContentStartPos>m_lContentStopPos) return "";
00580 
00581   return m_psLoadData->substr(m_lContentStartPos,m_lContentStopPos-m_lContentStartPos);
00582 };
00583 
00584 void
00585 XMLStreamObject::
00586 CommitSubElement()
00587 {
00588   if (m_lContentStopPos>-1) //there is a sub element finished
00589   {
00590     m_lElementStopPos = XML_GetCurrentByteIndex(m_Parser);
00591     SubElementLoadProcessing(m_sActSubElementTag,ExtractSubElementXmlString(),ExtractSubElementContentString());
00592     NotifyFoundSubElement(m_sActSubElementTag);
00593   }
00594   else if (m_lContentStartPos>-1) //there is xml text information
00595   {
00596     m_lContentStopPos = XML_GetCurrentByteIndex(m_Parser);
00597     SubElementLoadProcessing(cXML_Text,ExtractSubElementContentString(),ExtractSubElementContentString());
00598   };
00599 };
00600 
00601 std::string
00602 XMLStreamObject::
00603 ConvertAttributesToString(const AttributesSaveListType& rAttributes)
00604 {
00605   std::string sResult;
00606 
00607   AttributesSaveListType::const_iterator pos;
00608 
00609   for (pos = rAttributes.begin(); pos!= rAttributes.end(); pos++)
00610   {
00611     std::string sAttribut = pos->first + "=";
00612     
00613     if (pos->second.find_first_of('"') == -1) sAttribut += "\""+pos->second+"\"";
00614     else if (pos->second.find_first_of('\'') == -1) sAttribut += "'"+pos->second+"'";
00615     else throwStaticExceptionMacro("Attribute value contains \" and '. Invalid value, cannot be saved as xml attribute. Invalid Value: " << pos->second);
00616   
00617     sResult += sAttribut+" ";
00618   }
00619 
00620   if (sResult.size()!=0) sResult.resize(sResult.size()-1);
00621   //erase the last char (space) because not needed
00622 
00623   return sResult;
00624 };
00625 
00626 }//end of namespace FREE

Generated at Sat Oct 13 18:14:02 2007 for f.r.e.e. - Flexible Registration and Evaluation Engine by doxygen 1.5.3 written by Dimitri van Heesch, © 1997-2000