CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_0/src/FWCore/Modules/src/XMLOutputModule.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     Modules
00004 // Class  :     XMLOutputModule
00005 //
00006 // Implementation:
00007 //     <Notes on implementation>
00008 //
00009 // Original Author:  Chris Jones
00010 //         Created:  Fri Aug  4 20:45:44 EDT 2006
00011 //
00012 
00013 // system include files
00014 #include <fstream>
00015 #include <string>
00016 #include <iomanip>
00017 #include <map>
00018 #include <sstream>
00019 #include <algorithm>
00020 
00021 #include "Reflex/Base.h"
00022 #include "Reflex/Member.h"
00023 
00024 #include "FWCore/Framework/interface/Event.h"
00025 #include "DataFormats/Provenance/interface/BranchDescription.h"
00026 #include "DataFormats/Provenance/interface/Selections.h"
00027 
00028 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00029 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
00030 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
00031 
00032 #include "FWCore/Framework/interface/Frameworkfwd.h"
00033 #include "FWCore/Framework/interface/OutputModule.h"
00034 #include "FWCore/Framework/interface/GenericHandle.h"
00035 #include "FWCore/Framework/interface/MakerMacros.h"
00036 
00037 // user include files
00038 
00039 //
00040 // constants, enums and typedefs
00041 //
00042 
00043 namespace edm {
00044   class XMLOutputModule : public OutputModule {
00045 
00046    public:
00047       XMLOutputModule(ParameterSet const&);
00048       virtual ~XMLOutputModule();
00049       static void fillDescriptions(ConfigurationDescriptions& descriptions);
00050 
00051       // ---------- const member functions ---------------------
00052 
00053       // ---------- static member functions --------------------
00054 
00055       // ---------- member functions ---------------------------
00056 
00057    private:
00058       virtual void write(EventPrincipal const& e);
00059       virtual void writeLuminosityBlock(LuminosityBlockPrincipal const&) {}
00060       virtual void writeRun(RunPrincipal const&) {}
00061 
00062       XMLOutputModule(XMLOutputModule const&); // stop default
00063 
00064       XMLOutputModule const& operator=(XMLOutputModule const&); // stop default
00065 
00066       // ---------- member data --------------------------------
00067       std::ofstream stream_;
00068       std::string indentation_;
00069   };
00070 
00071   namespace {
00072     void doNotDelete(void*) {}
00073     void callDestruct(Reflex::Object* iObj) {
00074       iObj->Destruct();
00075     }
00076     //Handle memory for calls to Reflex Invoke
00077     // We handle Ref's by using an external void* buffer (which we do not delete) while everything else
00078     // we ask Reflex to create the proper object (and therefore must ask Reflex to delete it)
00079     boost::shared_ptr<Reflex::Object> initReturnValue(Reflex::Member const& iMember,
00080                                                       Reflex::Object* iObj,
00081                                                       void** iRefBuffer) {
00082       Reflex::Type returnType = iMember.TypeOf().ReturnType();
00083       if(returnType.IsReference()) {
00084         *iObj = Reflex::Object(returnType, iRefBuffer);
00085         return boost::shared_ptr<Reflex::Object>(iObj, doNotDelete);
00086       }
00087       *iObj = returnType.Construct();
00088       return boost::shared_ptr<Reflex::Object>(iObj, callDestruct);
00089     }
00090 
00091     //remove characters from a string which are not allowed to be used in XML
00092     std::string formatXML(std::string const& iO) {
00093       std::string result(iO);
00094       static std::string const kSubs("<>&");
00095       static std::string const kLeft("&lt;");
00096       static std::string const kRight("&gt;");
00097       static std::string const kAmp("&");
00098 
00099       std::string::size_type i = 0;
00100       while(std::string::npos != (i = result.find_first_of(kSubs, i))) {
00101         switch(result.at(i)) {
00102           case '<':
00103             result.replace(i, 1, kLeft);
00104             break;
00105           case '>':
00106             result.replace(i, 1, kRight);
00107             break;
00108           case '&':
00109             result.replace(i, 1, kAmp);
00110         }
00111         ++i;
00112       }
00113       return result;
00114     }
00115 
00116     char const* kNameValueSep = "\">";
00117     char const* kContainerOpen = "<container size=\"";
00118     char const* kContainerClose = "</container>";
00119     std::string const kObjectOpen = "<object type=\"";
00120     std::string const kObjectClose = "</object>";
00122     #define FILLNAME(_type_) s_toName[typeid(_type_).name()]= #_type_;
00123     std::string const& typeidToName(std::type_info const& iID) {
00124       static std::map<std::string, std::string> s_toName;
00125       if(s_toName.empty()) {
00126         FILLNAME(short);
00127         FILLNAME(int);
00128         FILLNAME(long);
00129         FILLNAME(long long);
00130 
00131         FILLNAME(unsigned short);
00132         FILLNAME(unsigned int);
00133         FILLNAME(unsigned long);
00134         FILLNAME(unsigned long long);
00135 
00136         FILLNAME(double);
00137         FILLNAME(float);
00138       }
00139       return s_toName[iID.name()];
00140     }
00141 
00142     template<typename T>
00143     void doPrint(std::ostream& oStream, std::string const& iPrefix, std::string const& iPostfix, Reflex::Object const& iObject, std::string const& iIndent) {
00144       oStream << iIndent << iPrefix << typeidToName(typeid(T)) << kNameValueSep
00145         << *reinterpret_cast<T*>(iObject.Address()) << iPostfix << "\n";
00146     }
00147 
00148     template<>
00149     void doPrint<char>(std::ostream& oStream, std::string const& iPrefix, std::string const& iPostfix, Reflex::Object const& iObject, std::string const& iIndent) {
00150       oStream << iIndent << iPrefix << "char" << kNameValueSep
00151         << static_cast<int>(*reinterpret_cast<char*>(iObject.Address())) << iPostfix << "\n";
00152     }
00153 
00154     template<>
00155     void doPrint<unsigned char>(std::ostream& oStream, std::string const& iPrefix, std::string const& iPostfix, Reflex::Object const& iObject, std::string const& iIndent) {
00156       oStream << iIndent << iPrefix << "unsigned char" << kNameValueSep << static_cast<unsigned int>(*reinterpret_cast<unsigned char*>(iObject.Address())) << iPostfix << "\n";
00157     }
00158 
00159     template<>
00160     void doPrint<bool>(std::ostream& oStream, std::string const& iPrefix, std::string const& iPostfix, Reflex::Object const& iObject, std::string const& iIndent) {
00161       oStream << iIndent << iPrefix << "bool" << kNameValueSep
00162         << ((*reinterpret_cast<bool*>(iObject.Address()))?"true":"false") << iPostfix << "\n";
00163     }
00164 
00165 
00166     typedef void(*FunctionType)(std::ostream&, std::string const&,
00167                                 std::string const&, Reflex::Object const&, std::string const&);
00168     typedef std::map<std::string, FunctionType> TypeToPrintMap;
00169 
00170     template<typename T>
00171     void addToMap(TypeToPrintMap& iMap){
00172       iMap[typeid(T).name()]=doPrint<T>;
00173     }
00174 
00175     bool printAsBuiltin(std::ostream& oStream,
00176                                std::string const& iPrefix,
00177                                std::string const& iPostfix,
00178                                Reflex::Object const iObject,
00179                                std::string const& iIndent){
00180       typedef void(*FunctionType)(std::ostream&, std::string const&, std::string const&, Reflex::Object const&, std::string const&);
00181       typedef std::map<std::string, FunctionType> TypeToPrintMap;
00182       static TypeToPrintMap s_map;
00183       static bool isFirst = true;
00184       if(isFirst){
00185         addToMap<bool>(s_map);
00186         addToMap<char>(s_map);
00187         addToMap<short>(s_map);
00188         addToMap<int>(s_map);
00189         addToMap<long>(s_map);
00190         addToMap<unsigned char>(s_map);
00191         addToMap<unsigned short>(s_map);
00192         addToMap<unsigned int>(s_map);
00193         addToMap<unsigned long>(s_map);
00194         addToMap<float>(s_map);
00195         addToMap<double>(s_map);
00196         isFirst=false;
00197       }
00198       TypeToPrintMap::iterator itFound =s_map.find(iObject.TypeOf().TypeInfo().name());
00199       if(itFound == s_map.end()){
00200 
00201         return false;
00202       }
00203       itFound->second(oStream, iPrefix, iPostfix, iObject, iIndent);
00204       return true;
00205     }
00206 
00207     bool printAsContainer(std::ostream& oStream,
00208                           std::string const& iPrefix,
00209                           std::string const& iPostfix,
00210                           Reflex::Object const& iObject,
00211                           std::string const& iIndent,
00212                           std::string const& iIndentDelta);
00213 
00214     void printDataMembers(std::ostream& oStream,
00215                           Reflex::Object const& iObject,
00216                           Reflex::Type const& iType,
00217                           std::string const& iIndent,
00218                           std::string const& iIndentDelta);
00219 
00220     void printObject(std::ostream& oStream,
00221                      std::string const& iPrefix,
00222                      std::string const& iPostfix,
00223                      Reflex::Object const& iObject,
00224                      std::string const& iIndent,
00225                      std::string const& iIndentDelta) {
00226       Reflex::Object objectToPrint = iObject;
00227       std::string indent(iIndent);
00228       if(iObject.TypeOf().IsPointer()) {
00229         oStream << iIndent << iPrefix << formatXML(iObject.TypeOf().Name(Reflex::SCOPED)) << "\">\n";
00230         indent +=iIndentDelta;
00231         int size = (0!=iObject.Address()) ? (0!=*reinterpret_cast<void**>(iObject.Address())?1:0) : 0;
00232         oStream << indent << kContainerOpen << size << "\">\n";
00233         if(size) {
00234           std::string indent2 = indent + iIndentDelta;
00235           Reflex::Object obj(iObject.TypeOf().ToType(), *reinterpret_cast<void**>(iObject.Address()));
00236           obj = obj.CastObject(obj.DynamicType());
00237           printObject(oStream, kObjectOpen, kObjectClose, obj, indent2, iIndentDelta);
00238         }
00239         oStream << indent << kContainerClose << "\n";
00240         oStream << iIndent << iPostfix << "\n";
00241         Reflex::Type pointedType = iObject.TypeOf().ToType();
00242         if(Reflex::Type::ByName("void") == pointedType || pointedType.IsPointer() || iObject.Address()==0) {
00243           return;
00244         }
00245         return;
00246         /*
00247         //have the code that follows print the contents of the data to which the pointer points
00248         objectToPrint = Reflex::Object(pointedType, iObject.Address());
00249         //try to convert it to its actual type (assuming the original type was a base class)
00250         objectToPrint = Reflex::Object(objectToPrint.CastObject(objectToPrint.DynamicType()));
00251         indent +=iIndentDelta;
00252         */
00253       }
00254       std::string typeName(objectToPrint.TypeOf().Name(Reflex::SCOPED));
00255       if(typeName.empty()){
00256         typeName="{unknown}";
00257       }
00258 
00259       //see if we are dealing with a typedef
00260       Reflex::Type objectType = objectToPrint.TypeOf();
00261       bool wasTypedef = false;
00262       while(objectType.IsTypedef()) {
00263          objectType = objectType.ToType();
00264          wasTypedef = true;
00265       }
00266       if(wasTypedef){
00267          Reflex::Object tmp(objectType, objectToPrint.Address());
00268          objectToPrint = tmp;
00269       }
00270       if(printAsBuiltin(oStream, iPrefix, iPostfix, objectToPrint, indent)) {
00271         return;
00272       }
00273       if(printAsContainer(oStream, iPrefix, iPostfix, objectToPrint, indent, iIndentDelta)){
00274         return;
00275       }
00276 
00277       oStream << indent << iPrefix << formatXML(typeName) << "\">\n";
00278       printDataMembers(oStream, objectToPrint, objectType, indent+iIndentDelta, iIndentDelta);
00279       oStream << indent << iPostfix << "\n";
00280 
00281     }
00282 
00283     void printDataMembers(std::ostream& oStream,
00284                           Reflex::Object const& iObject,
00285                           Reflex::Type const& iType,
00286                           std::string const& iIndent,
00287                           std::string const& iIndentDelta) {
00288       //print all the base class data members
00289       for(Reflex::Base_Iterator itBase = iType.Base_Begin();
00290           itBase != iType.Base_End();
00291           ++itBase) {
00292         printDataMembers(oStream, iObject.CastObject(itBase->ToType()), itBase->ToType(), iIndent, iIndentDelta);
00293       }
00294       static std::string const kPrefix("<datamember name=\"");
00295       static std::string const ktype("\" type=\"");
00296       static std::string const kPostfix("</datamember>");
00297 
00298       for(Reflex::Member_Iterator itMember = iType.DataMember_Begin();
00299           itMember != iType.DataMember_End();
00300           ++itMember){
00301         //std::cout << "     debug " << itMember->Name() << " " << itMember->TypeOf().Name() << "\n";
00302         if (itMember->IsTransient()) {
00303           continue;
00304         }
00305         try {
00306           std::string prefix = kPrefix + itMember->Name() + ktype;
00307           printObject(oStream,
00308                       prefix,
00309                       kPostfix,
00310                       itMember->Get(iObject),
00311                       iIndent,
00312                       iIndentDelta);
00313         }catch(std::exception& iEx) {
00314           std::cout << iIndent << itMember->Name() << " <exception caught("
00315           << iEx.what() << ")>\n";
00316         }
00317       }
00318     }
00319 
00320     bool printContentsOfStdContainer(std::ostream& oStream,
00321                                      std::string const& iPrefix,
00322                                      std::string const& iPostfix,
00323                                      Reflex::Object iBegin,
00324                                      Reflex::Object const& iEnd,
00325                                      std::string const& iIndent,
00326                                      std::string const& iIndentDelta){
00327       size_t size = 0;
00328       std::ostringstream sStream;
00329       if(iBegin.TypeOf() != iEnd.TypeOf()) {
00330         std::cerr << " begin (" << iBegin.TypeOf().Name(Reflex::SCOPED) << ") and end ("
00331           << iEnd.TypeOf().Name(Reflex::SCOPED) << ") are not the same type" << std::endl;
00332         throw std::exception();
00333       }
00334       try {
00335         Reflex::Member compare(iBegin.TypeOf().MemberByName("operator!="));
00336         if(!compare) {
00337           //std::cerr << "no 'operator!=' for " << iBegin.TypeOf().Name() << std::endl;
00338           return false;
00339         }
00340         Reflex::Member incr(iBegin.TypeOf().MemberByName("operator++"));
00341         if(!incr) {
00342           //std::cerr << "no 'operator++' for " << iBegin.TypeOf().Name() << std::endl;
00343           return false;
00344         }
00345         Reflex::Member deref(iBegin.TypeOf().MemberByName("operator*"));
00346         if(!deref) {
00347           //std::cerr << "no 'operator*' for " << iBegin.TypeOf().Name() << std::endl;
00348           return false;
00349         }
00350 
00351         std::string indexIndent = iIndent+iIndentDelta;
00352         int dummy=0;
00353         //std::cerr << "going to loop using iterator " << iBegin.TypeOf().Name(Reflex::SCOPED) << std::endl;
00354 
00355         std::vector<void*> compareArgs = Reflex::Tools::MakeVector((iEnd.Address()));
00356         std::vector<void*> incrArgs = Reflex::Tools::MakeVector(static_cast<void*>(&dummy));
00357         bool compareResult;
00358         Reflex::Object objCompareResult(Reflex::Type::ByTypeInfo(typeid(bool)), &compareResult);
00359         Reflex::Object objIncr;
00360         void* objIncrRefBuffer;
00361         boost::shared_ptr<Reflex::Object> incrMemHolder = initReturnValue(incr, &objIncr, &objIncrRefBuffer);
00362         for(;
00363           compare.Invoke(iBegin, &objCompareResult, compareArgs), compareResult;
00364           incr.Invoke(iBegin, &objIncr, incrArgs), ++size) {
00365           //std::cerr << "going to print" << std::endl;
00366           Reflex::Object iTemp;
00367           void* derefRefBuffer;
00368           boost::shared_ptr<Reflex::Object> derefMemHolder = initReturnValue(deref, &iTemp, &derefRefBuffer);
00369           deref.Invoke(iBegin, &iTemp);
00370           if(iTemp.TypeOf().IsReference()) {
00371             iTemp = Reflex::Object(iTemp.TypeOf(), derefRefBuffer);
00372           }
00373           printObject(sStream, kObjectOpen, kObjectClose, iTemp, indexIndent, iIndentDelta);
00374           //std::cerr << "printed" << std::endl;
00375         }
00376       } catch(std::exception const& iE) {
00377         std::cerr << "while printing std container caught exception " << iE.what() << std::endl;
00378         return false;
00379       }
00380       oStream << iPrefix << iIndent << kContainerOpen << size << "\">\n";
00381       oStream << sStream.str();
00382       oStream << iIndent << kContainerClose << std::endl;
00383       oStream << iPostfix;
00384       //std::cerr << "finished loop" << std::endl;
00385       return true;
00386     }
00387 
00388     bool printAsContainer(std::ostream& oStream,
00389                           std::string const& iPrefix, std::string const& iPostfix,
00390                           Reflex::Object const& iObject,
00391                           std::string const& iIndent,
00392                           std::string const& iIndentDelta) {
00393       Reflex::Object sizeObj;
00394       try {
00395         size_t temp; //used to hold the memory for the return value
00396         sizeObj = Reflex::Object(Reflex::Type::ByTypeInfo(typeid(size_t)), &temp);
00397         iObject.Invoke("size", &sizeObj);
00398 
00399         if(sizeObj.TypeOf().TypeInfo() != typeid(size_t)) {
00400           throw std::exception();
00401         }
00402         size_t size = *reinterpret_cast<size_t*>(sizeObj.Address());
00403         Reflex::Member atMember;
00404         atMember = iObject.TypeOf().MemberByName("at");
00405         if(!atMember) {
00406           throw std::exception();
00407         }
00408         std::string typeName(iObject.TypeOf().Name(Reflex::SCOPED));
00409         if(typeName.empty()){
00410           typeName="{unknown}";
00411         }
00412 
00413         oStream << iIndent << iPrefix << formatXML(typeName) << "\">\n"
00414           << iIndent << kContainerOpen << size << "\">\n";
00415         Reflex::Object contained;
00416         std::string indexIndent=iIndent+iIndentDelta;
00417         for(size_t index = 0; index != size; ++index) {
00418           void* atRefBuffer;
00419           boost::shared_ptr<Reflex::Object> atMemHolder = initReturnValue(atMember, &contained, &atRefBuffer);
00420 
00421           atMember.Invoke(iObject, &contained, Reflex::Tools::MakeVector(static_cast<void*>(&index)));
00422           if(contained.TypeOf().IsReference()) {
00423             contained = Reflex::Object(contained.TypeOf(), atRefBuffer);
00424           }
00425           //std::cout << "invoked 'at'" << std::endl;
00426           try {
00427             printObject(oStream, kObjectOpen, kObjectClose, contained, indexIndent, iIndentDelta);
00428           }catch(std::exception& iEx) {
00429             std::cout << iIndent << " <exception caught("
00430             << iEx.what() << ")>\n";
00431           }
00432         }
00433         oStream << iIndent << kContainerClose << std::endl;
00434         oStream << iIndent << iPostfix << std::endl;
00435         return true;
00436       } catch(std::exception const& x){
00437         //std::cerr << "failed to invoke 'at' because " << x.what() << std::endl;
00438         try {
00439           //oStream << iIndent << iPrefix << formatXML(typeName) << "\">\n";
00440           std::string typeName(iObject.TypeOf().Name(Reflex::SCOPED));
00441           if(typeName.empty()){
00442             typeName="{unknown}";
00443           }
00444           Reflex::Object iObjBegin;
00445           void* beginRefBuffer;
00446           Reflex::Member beginMember = iObject.TypeOf().MemberByName("begin");
00447           boost::shared_ptr<Reflex::Object> beginMemHolder = initReturnValue(beginMember, &iObjBegin, &beginRefBuffer);
00448           Reflex::Object iObjEnd;
00449           void* endRefBuffer;
00450           Reflex::Member endMember = iObject.TypeOf().MemberByName("end");
00451           boost::shared_ptr<Reflex::Object> endMemHolder = initReturnValue(endMember, &iObjEnd, &endRefBuffer);
00452 
00453           beginMember.Invoke(iObject, &iObjBegin);
00454           endMember.Invoke(iObject, &iObjEnd);
00455           if(printContentsOfStdContainer(oStream,
00456                                          iIndent+iPrefix+formatXML(typeName)+"\">\n",
00457                                          iIndent+iPostfix,
00458                                          iObjBegin,
00459                                          iObjEnd,
00460                                          iIndent,
00461                                          iIndentDelta)) {
00462             if(typeName.empty()){
00463               typeName="{unknown}";
00464             }
00465             return true;
00466           }
00467         } catch(std::exception const& x) {
00468         }
00469         return false;
00470       }
00471       return false;
00472     }
00473 
00474     void printObject(std::ostream& oStream,
00475                      Event const& iEvent,
00476                      std::string const& iClassName,
00477                      std::string const& iModuleLabel,
00478                      std::string const& iInstanceLabel,
00479                      std::string const& iIndent,
00480                      std::string const& iIndentDelta) {
00481       try {
00482         GenericHandle handle(iClassName);
00483       }catch(edm::Exception const&) {
00484         std::cout << iIndent << " \"" << iClassName << "\"" << " is an unknown type" << std::endl;
00485         return;
00486       }
00487       GenericHandle handle(iClassName);
00488       iEvent.getByLabel(iModuleLabel, iInstanceLabel, handle);
00489       std::string className = formatXML(iClassName);
00490       printObject(oStream, kObjectOpen, kObjectClose, *handle, iIndent, iIndentDelta);
00491     }
00492   }
00493 
00494   //
00495   // static data member definitions
00496   //
00497 
00498   //
00499   // constructors and destructor
00500   //
00501   XMLOutputModule::XMLOutputModule(ParameterSet const& iPSet) :
00502       OutputModule(iPSet),
00503       stream_(iPSet.getUntrackedParameter<std::string>("fileName").c_str()),
00504       indentation_("  ") {
00505     if(!stream_){
00506       throw edm::Exception(errors::Configuration) << "failed to open file " << iPSet.getUntrackedParameter<std::string>("fileName");
00507     }
00508     stream_ << "<cmsdata>" << std::endl;
00509   }
00510 
00511   // XMLOutputModule::XMLOutputModule(XMLOutputModule const& rhs)
00512   // {
00513   //    // do actual copying here;
00514   // }
00515 
00516   XMLOutputModule::~XMLOutputModule() {
00517     stream_ << "</cmsdata>" << std::endl;
00518   }
00519 
00520   //
00521   // assignment operators
00522   //
00523   // XMLOutputModule const& XMLOutputModule::operator=(XMLOutputModule const& rhs)
00524   // {
00525   //   //An exception safe implementation is
00526   //   XMLOutputModule temp(rhs);
00527   //   swap(rhs);
00528   //
00529   //   return *this;
00530   // }
00531 
00532   //
00533   // member functions
00534   //
00535   void
00536   XMLOutputModule::write(EventPrincipal const& iEP) {
00537     ModuleDescription desc;
00538     Event event(const_cast<EventPrincipal&>(iEP), desc);
00539     stream_ << "<event run=\"" << event.id().run() << "\" number=\"" << event.id().event() << "\" >\n";
00540     std::string startIndent = indentation_;
00541     for(Selections::const_iterator itBD = keptProducts()[InEvent].begin(), itBDEnd = keptProducts()[InEvent].end();
00542         itBD != itBDEnd;
00543         ++itBD) {
00544       stream_ << "<product type=\"" << (*itBD)->friendlyClassName()
00545              << "\" module=\"" << (*itBD)->moduleLabel()
00546       << "\" productInstance=\"" << (*itBD)->productInstanceName() << "\">\n";
00547       printObject(stream_,
00548                    event,
00549                   (*itBD)->className(),
00550                   (*itBD)->moduleLabel(),
00551                   (*itBD)->productInstanceName(),
00552                   startIndent,
00553                   indentation_);
00554       stream_ << "</product>\n";
00555     }
00556     stream_ << "</event>" << std::endl;
00557   }
00558 
00559   void
00560   XMLOutputModule::fillDescriptions(ConfigurationDescriptions& descriptions) {
00561     ParameterSetDescription desc;
00562     desc.setComment("Prints event information into a file in XML format.");
00563     desc.addUntracked<std::string>("fileName");
00564     OutputModule::fillDescription(desc);
00565     descriptions.add("XMLoutput", desc);
00566   }
00567 }
00568 using edm::XMLOutputModule;
00569 DEFINE_FWK_MODULE(XMLOutputModule);