Home  · Classes  · Annotated Classes  · Modules  · Members  · Namespaces  · Related Pages

MzXMLHandler.h

Go to the documentation of this file.
00001 // --------------------------------------------------------------------------
00002 //                   OpenMS -- Open-Source Mass Spectrometry
00003 // --------------------------------------------------------------------------
00004 // Copyright The OpenMS Team -- Eberhard Karls University Tuebingen,
00005 // ETH Zurich, and Freie Universitaet Berlin 2002-2012.
00006 //
00007 // This software is released under a three-clause BSD license:
00008 //  * Redistributions of source code must retain the above copyright
00009 //    notice, this list of conditions and the following disclaimer.
00010 //  * Redistributions in binary form must reproduce the above copyright
00011 //    notice, this list of conditions and the following disclaimer in the
00012 //    documentation and/or other materials provided with the distribution.
00013 //  * Neither the name of any author or any participating institution
00014 //    may be used to endorse or promote products derived from this software
00015 //    without specific prior written permission.
00016 // For a full list of authors, refer to the file AUTHORS.
00017 // --------------------------------------------------------------------------
00018 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 // ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING
00022 // INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00023 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00024 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
00025 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00026 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00027 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00028 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 //
00030 // --------------------------------------------------------------------------
00031 // $Maintainer: Andreas Bertsch $
00032 // $Authors: Marc Sturm $
00033 // --------------------------------------------------------------------------
00034 
00035 #ifndef OPENMS_FORMAT_HANDLERS_MZXMLHANDLER_H
00036 #define OPENMS_FORMAT_HANDLERS_MZXMLHANDLER_H
00037 
00038 #include <OpenMS/CONCEPT/ProgressLogger.h>
00039 #include <OpenMS/FORMAT/Base64.h>
00040 #include <OpenMS/FORMAT/OPTIONS/PeakFileOptions.h>
00041 #include <OpenMS/FORMAT/HANDLERS/XMLHandler.h>
00042 #include <OpenMS/DATASTRUCTURES/String.h>
00043 #include <OpenMS/KERNEL/MSExperiment.h>
00044 
00045 #include <stack>
00046 
00047 namespace OpenMS
00048 {
00049   class MetaInfoInterface;
00050 
00051   namespace Internal
00052   {
00059     template <typename MapType>
00060     class MzXMLHandler :
00061       public XMLHandler
00062     {
00063 public:
00066 
00067       MzXMLHandler(MapType & exp, const String & filename, const String & version, ProgressLogger & logger) :
00068         XMLHandler(filename, version),
00069         exp_(&exp),
00070         cexp_(0),
00071         decoder_(),
00072         peak_count_(0),
00073         char_rest_(),
00074         skip_spectrum_(false),
00075         spec_write_counter_(1),
00076         logger_(logger)
00077       {
00078         init_();
00079       }
00080 
00082       MzXMLHandler(const MapType & exp, const String & filename, const String & version, const ProgressLogger & logger) :
00083         XMLHandler(filename, version),
00084         exp_(0),
00085         cexp_(&exp),
00086         decoder_(),
00087         peak_count_(0),
00088         char_rest_(),
00089         skip_spectrum_(false),
00090         spec_write_counter_(1),
00091         logger_(logger)
00092       {
00093         init_();
00094       }
00095 
00097       virtual ~MzXMLHandler()
00098       {
00099       }
00100 
00102 
00103       // Docu in base class
00104       virtual void endElement(const XMLCh * const uri, const XMLCh * const local_name, const XMLCh * const qname);
00105 
00106       // Docu in base class
00107       virtual void startElement(const XMLCh * const uri, const XMLCh * const local_name, const XMLCh * const qname, const xercesc::Attributes & attributes);
00108 
00109       // Docu in base class
00110       virtual void characters(const XMLCh * const chars, const XMLSize_t length);
00111 
00113       void writeTo(std::ostream & os);
00114 
00116       void setOptions(const PeakFileOptions & options)
00117       {
00118         options_ = options;
00119       }
00120 
00121 private:
00122       // initialize members (call from C'tor)
00123       void init_()
00124       {
00125         cv_terms_.resize(6);
00126         //Polarity
00127         String("any;+;-").split(';', cv_terms_[0]);
00128         //Scan type
00129         // is no longer used cv_terms_[1] is empty now
00130         //Ionization method
00131         String(";ESI;EI;CI;FAB;;;;;;;;;;;;;APCI;;;;;;;;MALDI").split(';', cv_terms_[2]);
00132         cv_terms_[2].resize(IonSource::SIZE_OF_IONIZATIONMETHOD);
00133         //Mass analyzer
00134         String(";Quadrupole;Quadrupole Ion Trap;;;TOF;Magnetic Sector;FT-ICR;").split(';', cv_terms_[3]);
00135         cv_terms_[3].resize(MassAnalyzer::SIZE_OF_ANALYZERTYPE);
00136         //Detector
00137         String(";EMT;;;Faraday Cup;;;;;Channeltron;Daly;Microchannel plate").split(';', cv_terms_[4]);
00138         cv_terms_[4].resize(IonDetector::SIZE_OF_TYPE);
00139         //Resolution method
00140         String(";FWHM;TenPercentValley;Baseline").split(';', cv_terms_[5]);
00141         cv_terms_[5].resize(MassAnalyzer::SIZE_OF_RESOLUTIONMETHOD);
00142         /* // OLD:
00143             cv_terms_.resize(6);
00144             //Polarity
00145             String("any;+;-").split(';',cv_terms_[0]);
00146             //Scan type
00147             // is no longer used cv_terms_[1] is empty now
00148             //Ionization method
00149             String(";ESI;EI;CI;FAB;TSP;MALDI;FD;FI;PD;SI;TI;API;ISI;CID;CAD;HN;APCI;APPI;ICP").split(';',cv_terms_[2]);
00150             //Mass analyzer
00151             String(";Quadrupole;Quadrupole Ion Trap;;;TOF;Magnetic Sector;FT-ICR;").split(';',cv_terms_[3]);
00152             //Detector
00153             String(";EMT;Daly;;Faraday Cup;;;;Channeltron").split(';',cv_terms_[4]);
00154             //Resolution method
00155             String(";FWHM;TenPercentValley;Baseline").split(';',cv_terms_[5]);
00156             */
00157       }
00158 
00159 protected:
00160 
00162       typedef typename MapType::PeakType PeakType;
00164       typedef MSSpectrum<PeakType> SpectrumType;
00165 
00166       typedef typename SpectrumType::Iterator  PeakIterator;
00167 
00169       MapType * exp_;
00171       const MapType * cexp_;
00172 
00174       PeakFileOptions options_;
00175 
00178       Base64 decoder_;
00179       UInt peak_count_;
00180       String precision_;
00181       String compressionType_;
00182       String char_rest_;
00184 
00186       bool skip_spectrum_;
00187 
00189       UInt spec_write_counter_;
00190 
00192       const ProgressLogger & logger_;
00193 
00195       inline void writeUserParam_(std::ostream & os, const MetaInfoInterface & meta, int indent = 4, String tag = "nameValue")
00196       {
00197         std::vector<String> keys;              // Vector to hold keys to meta info
00198         meta.getKeys(keys);
00199 
00200         for (std::vector<String>::const_iterator it = keys.begin(); it != keys.end(); ++it)
00201         {
00202           if ((*it)[0] != '#')                 // internally used meta info start with '#'
00203           {
00204             os << String(indent, '\t') << "<" << tag << " name=\"" << *it << "\" value=\"" << meta.getMetaValue(*it) << "\"/>\n";
00205           }
00206         }
00207       }
00208 
00210       std::vector<DataProcessing> data_processing_;
00211 
00212 private:
00214       MzXMLHandler();
00215 
00216       static const XMLCh * s_value_;
00217       static const XMLCh * s_count_;
00218       static const XMLCh * s_type_;
00219       static const XMLCh * s_name_;
00220       static const XMLCh * s_version_;
00221       static const XMLCh * s_filename_;
00222       static const XMLCh * s_filetype_;
00223       static const XMLCh * s_filesha1_;
00224       static const XMLCh * s_completiontime_;
00225       static const XMLCh * s_precision_;
00226       static const XMLCh * s_byteorder_;
00227       static const XMLCh * s_pairorder_;
00228       static const XMLCh * s_compressionType_;
00229       static const XMLCh * s_precursorintensity_;
00230       static const XMLCh * s_precursorcharge_;
00231       static const XMLCh * s_windowwideness_;
00232       static const XMLCh * s_mslevel_;
00233       static const XMLCh * s_peakscount_;
00234       static const XMLCh * s_polarity_;
00235       static const XMLCh * s_scantype_;
00236       static const XMLCh * s_retentiontime_;
00237       static const XMLCh * s_startmz_;
00238       static const XMLCh * s_endmz_;
00239       static const XMLCh * s_first_;
00240       static const XMLCh * s_last_;
00241       static const XMLCh * s_phone_;
00242       static const XMLCh * s_email_;
00243       static const XMLCh * s_uri_;
00244       static const XMLCh * s_num_;
00245       static const XMLCh * s_intensitycutoff_;
00246       static const XMLCh * s_centroided_;
00247       static const XMLCh * s_deisotoped_;
00248       static const XMLCh * s_chargedeconvoluted_;
00249 
00250       // init all the static members, which is necessary because otherwise the undefined order will cause problems
00251       void initStaticMembers_()
00252       {
00253         static bool init(false);
00254         if (!init)
00255         {
00256           s_value_ = xercesc::XMLString::transcode("value");
00257           s_count_ = xercesc::XMLString::transcode("scanCount");
00258           s_type_ = xercesc::XMLString::transcode("type");
00259           s_name_ = xercesc::XMLString::transcode("name");
00260           s_version_ = xercesc::XMLString::transcode("version");
00261           s_filename_ = xercesc::XMLString::transcode("fileName");
00262           s_filetype_ = xercesc::XMLString::transcode("fileType");
00263           s_filesha1_ = xercesc::XMLString::transcode("fileSha1");
00264           s_completiontime_ = xercesc::XMLString::transcode("completionTime");
00265           s_precision_ = xercesc::XMLString::transcode("precision");
00266           s_byteorder_ = xercesc::XMLString::transcode("byteOrder");
00267           s_pairorder_ = xercesc::XMLString::transcode("pairOrder");
00268           s_compressionType_ = xercesc::XMLString::transcode("compressionType");
00269           s_precursorintensity_ = xercesc::XMLString::transcode("precursorIntensity");
00270           s_precursorcharge_ = xercesc::XMLString::transcode("precursorCharge");
00271           s_windowwideness_ = xercesc::XMLString::transcode("windowWideness");
00272           s_mslevel_ = xercesc::XMLString::transcode("msLevel");
00273           s_peakscount_ = xercesc::XMLString::transcode("peaksCount");
00274           s_polarity_ = xercesc::XMLString::transcode("polarity");
00275           s_scantype_ = xercesc::XMLString::transcode("scanType");
00276           s_retentiontime_ = xercesc::XMLString::transcode("retentionTime");
00277           s_startmz_ = xercesc::XMLString::transcode("startMz");
00278           s_endmz_ = xercesc::XMLString::transcode("endMz");
00279           s_first_ = xercesc::XMLString::transcode("first");
00280           s_last_ = xercesc::XMLString::transcode("last");
00281           s_phone_ = xercesc::XMLString::transcode("phone");
00282           s_email_ = xercesc::XMLString::transcode("email");
00283           s_uri_ = xercesc::XMLString::transcode("URI");
00284           s_num_ = xercesc::XMLString::transcode("num");
00285           s_intensitycutoff_ = xercesc::XMLString::transcode("intensityCutoff");
00286           s_centroided_ = xercesc::XMLString::transcode("centroided");
00287           s_deisotoped_ = xercesc::XMLString::transcode("deisotoped");
00288           s_chargedeconvoluted_ = xercesc::XMLString::transcode("chargeDeconvoluted");
00289 
00290           init = true;
00291         }
00292         return;
00293       }
00294 
00295     };
00296 
00297     //--------------------------------------------------------------------------------
00298 
00299     // this cannot be moved into a function as VS2008 does not allow more than 31 static members in a function .. don't ask...
00300     template <typename MapType>
00301     const XMLCh * MzXMLHandler<MapType>::s_value_ = 0;
00302     template <typename MapType>
00303     const XMLCh * MzXMLHandler<MapType>::s_count_ = 0;
00304     template <typename MapType>
00305     const XMLCh * MzXMLHandler<MapType>::s_type_ = 0;
00306     template <typename MapType>
00307     const XMLCh * MzXMLHandler<MapType>::s_name_ = 0;
00308     template <typename MapType>
00309     const XMLCh * MzXMLHandler<MapType>::s_version_ = 0;
00310     template <typename MapType>
00311     const XMLCh * MzXMLHandler<MapType>::s_filename_ = 0;
00312     template <typename MapType>
00313     const XMLCh * MzXMLHandler<MapType>::s_filetype_ = 0;
00314     template <typename MapType>
00315     const XMLCh * MzXMLHandler<MapType>::s_filesha1_ = 0;
00316     template <typename MapType>
00317     const XMLCh * MzXMLHandler<MapType>::s_completiontime_ = 0;
00318     template <typename MapType>
00319     const XMLCh * MzXMLHandler<MapType>::s_precision_ = 0;
00320     template <typename MapType>
00321     const XMLCh * MzXMLHandler<MapType>::s_byteorder_ = 0;
00322     template <typename MapType>
00323     const XMLCh * MzXMLHandler<MapType>::s_pairorder_ = 0;
00324     template <typename MapType>
00325     const XMLCh * MzXMLHandler<MapType>::s_compressionType_ = 0;
00326     template <typename MapType>
00327     const XMLCh * MzXMLHandler<MapType>::s_precursorintensity_ = 0;
00328     template <typename MapType>
00329     const XMLCh * MzXMLHandler<MapType>::s_precursorcharge_ = 0;
00330     template <typename MapType>
00331     const XMLCh * MzXMLHandler<MapType>::s_windowwideness_ = 0;
00332     template <typename MapType>
00333     const XMLCh * MzXMLHandler<MapType>::s_mslevel_ = 0;
00334     template <typename MapType>
00335     const XMLCh * MzXMLHandler<MapType>::s_peakscount_ = 0;
00336     template <typename MapType>
00337     const XMLCh * MzXMLHandler<MapType>::s_polarity_ = 0;
00338     template <typename MapType>
00339     const XMLCh * MzXMLHandler<MapType>::s_scantype_ = 0;
00340     template <typename MapType>
00341     const XMLCh * MzXMLHandler<MapType>::s_retentiontime_ = 0;
00342     template <typename MapType>
00343     const XMLCh * MzXMLHandler<MapType>::s_startmz_ = 0;
00344     template <typename MapType>
00345     const XMLCh * MzXMLHandler<MapType>::s_endmz_ = 0;
00346     template <typename MapType>
00347     const XMLCh * MzXMLHandler<MapType>::s_first_ = 0;
00348     template <typename MapType>
00349     const XMLCh * MzXMLHandler<MapType>::s_last_ = 0;
00350     template <typename MapType>
00351     const XMLCh * MzXMLHandler<MapType>::s_phone_ = 0;
00352     template <typename MapType>
00353     const XMLCh * MzXMLHandler<MapType>::s_email_ = 0;
00354     template <typename MapType>
00355     const XMLCh * MzXMLHandler<MapType>::s_uri_ = 0;
00356     template <typename MapType>
00357     const XMLCh * MzXMLHandler<MapType>::s_num_ = 0;
00358     template <typename MapType>
00359     const XMLCh * MzXMLHandler<MapType>::s_intensitycutoff_ = 0;
00360     template <typename MapType>
00361     const XMLCh * MzXMLHandler<MapType>::s_centroided_ = 0;
00362     template <typename MapType>
00363     const XMLCh * MzXMLHandler<MapType>::s_deisotoped_ = 0;
00364     template <typename MapType>
00365     const XMLCh * MzXMLHandler<MapType>::s_chargedeconvoluted_ = 0;
00366 
00367     template <typename MapType>
00368     void MzXMLHandler<MapType>::startElement(const XMLCh * const /*uri*/, const XMLCh * const /*local_name*/, const XMLCh * const qname, const xercesc::Attributes & attributes)
00369     {
00370       static bool init_static_members(false);
00371       if (!init_static_members)
00372       {
00373         initStaticMembers_();
00374       }
00375 
00376       static UInt scan_count = 0;
00377 
00378       String tag = sm_.convert(qname);
00379       open_tags_.push_back(tag);
00380       //std::cout << " -- Start -- "<< tag << " -- " << "\n";
00381 
00382       //Skip all tags until the the next scan
00383       if (skip_spectrum_ && tag != "scan")
00384         return;
00385 
00386       if (tag == "msRun")
00387       {
00388         Int count = 0;
00389         optionalAttributeAsInt_(count, attributes, s_count_);
00390         exp_->reserve(count);
00391         logger_.startProgress(0, count, "loading mzXML file");
00392         scan_count = 0;
00393         data_processing_.clear();
00394         //start and end time are xs:duration. This makes no senes => ignore them
00395       }
00396       else if (tag == "parentFile")
00397       {
00398         SourceFile sf;
00399         sf.setNameOfFile(attributeAsString_(attributes, s_filename_));
00400         sf.setFileType(attributeAsString_(attributes, s_filetype_));
00401         sf.setChecksum(attributeAsString_(attributes, s_filesha1_), SourceFile::SHA1);
00402         exp_->getSourceFiles().push_back(sf);
00403       }
00404       else if (tag == "software")
00405       {
00406         String & parent_tag = *(open_tags_.end() - 2);
00407         if (parent_tag == "dataProcessing")
00408         {
00409           data_processing_.back().getSoftware().setVersion(attributeAsString_(attributes, s_version_));
00410           data_processing_.back().getSoftware().setName(attributeAsString_(attributes, s_name_));
00411           data_processing_.back().setMetaValue("#type", String(attributeAsString_(attributes, s_type_)));
00412 
00413           String time;
00414           optionalAttributeAsString_(time, attributes, s_completiontime_);
00415           data_processing_.back().setCompletionTime(asDateTime_(time));
00416         }
00417         else if (parent_tag == "msInstrument")
00418         {
00419           exp_->getInstrument().getSoftware().setVersion(attributeAsString_(attributes, s_version_));
00420           exp_->getInstrument().getSoftware().setName(attributeAsString_(attributes, s_name_));
00421         }
00422       }
00423       else if (tag == "peaks")
00424       {
00425         //precision
00426         precision_ = "32";
00427         optionalAttributeAsString_(precision_, attributes, s_precision_);
00428         if (precision_ != "32" && precision_ != "64")
00429         {
00430           error(LOAD, String("Invalid precision '") + precision_ + "' in element 'peaks'");
00431         }
00432         //byte order
00433         String byte_order = "network";
00434         optionalAttributeAsString_(byte_order, attributes, s_byteorder_);
00435         if (byte_order != "network")
00436         {
00437           error(LOAD, String("Invalid or missing byte order '") + byte_order + "' in element 'peaks'. Must be 'network'!");
00438         }
00439         //pair order
00440         String pair_order = "m/z-int";
00441         optionalAttributeAsString_(pair_order, attributes, s_pairorder_);
00442         if (pair_order != "m/z-int")
00443         {
00444           error(LOAD, String("Invalid or missing pair order '") + pair_order + "' in element 'peaks'. Must be 'm/z-int'!");
00445         }
00446         //compressionType
00447         compressionType_ = "none";
00448         optionalAttributeAsString_(compressionType_, attributes, s_compressionType_);
00449         if (compressionType_ != "none" && compressionType_ != "zlib")
00450         {
00451           error(LOAD, String("Invalid compression type ") +  compressionType_ + "in elements 'peaks'. Must be 'none' or 'zlib'! ");
00452         }
00453       }
00454       else if (tag == "precursorMz")
00455       {
00456         //add new precursor
00457         exp_->back().getPrecursors().push_back(Precursor());
00458         //intensity
00459         try
00460         {
00461           exp_->back().getPrecursors().back().setIntensity(attributeAsDouble_(attributes, s_precursorintensity_));
00462         }
00463         catch (Exception::ParseError & /*e*/)
00464         {
00465           error(LOAD, "Mandatory attribute 'precursorIntensity' of tag 'precursorMz' not found! Setting precursor intensity to zero!");
00466         }
00467         //charge
00468         Int charge = 0;
00469         if (optionalAttributeAsInt_(charge, attributes, s_precursorcharge_))
00470         {
00471           exp_->back().getPrecursors().back().setCharge(charge);
00472         }
00473         //window bounds (here only the width is stored in both fields - this is corrected when we parse the m/z position)
00474         DoubleReal window = 0.0;
00475         if (optionalAttributeAsDouble_(window, attributes, s_windowwideness_))
00476         {
00477           exp_->back().getPrecursors().back().setIsolationWindowLowerOffset(window);
00478         }
00479       }
00480       else if (tag == "scan")
00481       {
00482         skip_spectrum_ = false;
00483 
00484         if (options_.getMetadataOnly())
00485           throw EndParsingSoftly(__FILE__, __LINE__, __PRETTY_FUNCTION__);
00486 
00487         // check if the scan is in the desired MS / RT range
00488         UInt ms_level = attributeAsInt_(attributes, s_mslevel_);
00489         if (ms_level == 0)
00490         {
00491           warning(LOAD, String("Invalid 'msLevel' attribute with value '0' in 'scan' element found. Assuming ms level 1!"));
00492           ms_level = 1;
00493         }
00494 
00495         //parse retention time and convert it from xs:duration to seconds
00496         DoubleReal retention_time = 0.0;
00497         String time_string = "";
00498         if (optionalAttributeAsString_(time_string, attributes, s_retentiontime_))
00499         {
00500           time_string = time_string.suffix('T');
00501           //std::cout << "Initial trim: " << time_string << "\n";
00502           if (time_string.has('H'))
00503           {
00504             retention_time += 3600 * asDouble_(time_string.prefix('H'));
00505             time_string = time_string.suffix('H');
00506             //std::cout << "After H: " << time_string << "\n";
00507           }
00508           if (time_string.has('M'))
00509           {
00510             retention_time += 60 * asDouble_(time_string.prefix('M'));
00511             time_string = time_string.suffix('M');
00512             //std::cout << "After M: " << time_string << "\n";
00513           }
00514           if (time_string.has('S'))
00515           {
00516             retention_time += asDouble_(time_string.prefix('S'));
00517             time_string = time_string.suffix('S');
00518             //std::cout << "After S: " << time_string << "\n";
00519           }
00520         }
00521 
00522         logger_.setProgress(scan_count);
00523 
00524         if ((options_.hasRTRange() && !options_.getRTRange().encloses(DPosition<1>(retention_time)))
00525            || (options_.hasMSLevels() && !options_.containsMSLevel(ms_level)))
00526         {
00527           // skip this tag
00528           skip_spectrum_ = true;
00529           ++scan_count;
00530           return;
00531         }
00532 
00533         //Add a new spectrum and set MS level and RT
00534         exp_->resize(exp_->size() + 1);
00535         exp_->back().setMSLevel(ms_level);
00536         exp_->back().setRT(retention_time);
00537         exp_->back().setNativeID(String("scan=") + attributeAsString_(attributes, s_num_));
00538         //peak count == twice the scan size
00539         peak_count_ = attributeAsInt_(attributes, s_peakscount_);
00540         exp_->back().reserve(peak_count_ / 2 + 1);
00541         exp_->back().setDataProcessing(data_processing_);
00542 
00543         //centroided, chargeDeconvoluted, deisotoped, collisionEnergy are ignored
00544 
00545         //other optional attributes
00546         ScanWindow window;
00547         optionalAttributeAsDouble_(window.begin, attributes, s_startmz_);
00548         optionalAttributeAsDouble_(window.end, attributes, s_endmz_);
00549         if (window.begin != 0.0 || window.end != 0.0)
00550         {
00551           exp_->back().getInstrumentSettings().getScanWindows().push_back(window);
00552         }
00553 
00554         String polarity = "any";
00555         optionalAttributeAsString_(polarity, attributes, s_polarity_);
00556         exp_->back().getInstrumentSettings().setPolarity((IonSource::Polarity) cvStringToEnum_(0, polarity, "polarity"));
00557 
00558         String type = "";
00559         optionalAttributeAsString_(type, attributes, s_scantype_);
00560         if (type == "")
00561         {
00562           //unknown/unset => do nothing here => no warning in the end
00563         }
00564         else if (type == "zoom")
00565         {
00566           exp_->back().getInstrumentSettings().setZoomScan(true);
00567           exp_->back().getInstrumentSettings().setScanMode(InstrumentSettings::MASSSPECTRUM);
00568         }
00569         else if (type == "Full")
00570         {
00571           if (ms_level > 1)
00572             exp_->back().getInstrumentSettings().setScanMode(InstrumentSettings::MSNSPECTRUM);
00573           else
00574             exp_->back().getInstrumentSettings().setScanMode(InstrumentSettings::MASSSPECTRUM);
00575         }
00576         else if (type == "SIM")
00577         {
00578           exp_->back().getInstrumentSettings().setScanMode(InstrumentSettings::SIM);
00579         }
00580         else if (type == "SRM" || type == "MRM")
00581         {
00582           exp_->back().getInstrumentSettings().setScanMode(InstrumentSettings::SRM);
00583         }
00584         else if (type == "CRM")
00585         {
00586           exp_->back().getInstrumentSettings().setScanMode(InstrumentSettings::CRM);
00587         }
00588         else if (type == "Q1")
00589         {
00590           exp_->back().getInstrumentSettings().setScanMode(InstrumentSettings::MASSSPECTRUM);
00591         }
00592         else if (type == "Q3")
00593         {
00594           exp_->back().getInstrumentSettings().setScanMode(InstrumentSettings::MASSSPECTRUM);
00595         }
00596         else if (type == "EMS")      //Non-standard type: Enhanced MS (ABI - Sashimi converter)
00597         {
00598           exp_->back().getInstrumentSettings().setScanMode(InstrumentSettings::MASSSPECTRUM);
00599         }
00600         else if (type == "EPI")      //Non-standard type: Enhanced Product Ion (ABI - Sashimi converter)
00601         {
00602           exp_->back().getInstrumentSettings().setScanMode(InstrumentSettings::MASSSPECTRUM);
00603           exp_->back().setMSLevel(2);
00604         }
00605         else if (type == "ER")       // Non-standard type: Enhanced Resolution (ABI - Sashimi converter)
00606         {
00607           exp_->back().getInstrumentSettings().setZoomScan(true);
00608           exp_->back().getInstrumentSettings().setScanMode(InstrumentSettings::MASSSPECTRUM);
00609         }
00610         else
00611         {
00612           exp_->back().getInstrumentSettings().setScanMode(InstrumentSettings::MASSSPECTRUM);
00613           warning(LOAD, String("Unknown scan mode '") + type + "'. Assuming full scan");
00614         }
00615 
00616         ++scan_count;
00617       }
00618       else if (tag == "operator")
00619       {
00620         exp_->getContacts().resize(1);
00621         exp_->getContacts().back().setFirstName(attributeAsString_(attributes, s_first_));
00622         exp_->getContacts().back().setLastName(attributeAsString_(attributes, s_last_));
00623 
00624         String tmp = "";
00625         optionalAttributeAsString_(tmp, attributes, s_email_);
00626         exp_->getContacts().back().setEmail(tmp);
00627 
00628         tmp = "";
00629         optionalAttributeAsString_(tmp, attributes, s_phone_);
00630         if (tmp != "")
00631         {
00632           exp_->getContacts().back().setMetaValue("#phone", tmp);
00633         }
00634 
00635         tmp = "";
00636         optionalAttributeAsString_(tmp, attributes, s_uri_);
00637         exp_->getContacts().back().setURL(tmp);
00638       }
00639       else if (tag == "msManufacturer")
00640       {
00641         exp_->getInstrument().setVendor(attributeAsString_(attributes, s_value_));
00642       }
00643       else if (tag == "msModel")
00644       {
00645         exp_->getInstrument().setModel(attributeAsString_(attributes, s_value_));
00646       }
00647       else if (tag == "msIonisation")
00648       {
00649         exp_->getInstrument().getIonSources().resize(1);
00650         exp_->getInstrument().getIonSources()[0].setIonizationMethod((IonSource::IonizationMethod) cvStringToEnum_(2, attributeAsString_(attributes, s_value_), "msIonization"));
00651       }
00652       else if (tag == "msMassAnalyzer")
00653       {
00654         exp_->getInstrument().getMassAnalyzers().resize(1);
00655         exp_->getInstrument().getMassAnalyzers()[0].setType((MassAnalyzer::AnalyzerType) cvStringToEnum_(3, attributeAsString_(attributes, s_value_), "msMassAnalyzer"));
00656       }
00657       else if (tag == "msDetector")
00658       {
00659         exp_->getInstrument().getIonDetectors().resize(1);
00660         exp_->getInstrument().getIonDetectors()[0].setType((IonDetector::Type) cvStringToEnum_(4, attributeAsString_(attributes, s_value_), "msDetector"));
00661       }
00662       else if (tag == "msResolution")
00663       {
00664         exp_->getInstrument().getMassAnalyzers()[0].setResolutionMethod((MassAnalyzer::ResolutionMethod) cvStringToEnum_(5, attributeAsString_(attributes, s_value_), "msResolution"));
00665       }
00666       else if (tag == "dataProcessing")
00667       {
00668         data_processing_.push_back(DataProcessing());
00669 
00670         String boolean = "";
00671         optionalAttributeAsString_(boolean, attributes, s_deisotoped_);
00672         if (boolean == "true" || boolean == "1")
00673         {
00674           data_processing_.back().getProcessingActions().insert(DataProcessing::DEISOTOPING);
00675         }
00676 
00677         boolean = "";
00678         optionalAttributeAsString_(boolean, attributes, s_chargedeconvoluted_);
00679         if (boolean == "true" || boolean == "1")
00680         {
00681           data_processing_.back().getProcessingActions().insert(DataProcessing::CHARGE_DECONVOLUTION);
00682         }
00683 
00684         DoubleReal cutoff = 0.0;
00685         optionalAttributeAsDouble_(cutoff, attributes, s_intensitycutoff_);
00686         if (cutoff != 0.0)
00687         {
00688           data_processing_.back().setMetaValue("#intensity_cutoff", cutoff);
00689         }
00690 
00691         boolean = "";
00692         optionalAttributeAsString_(boolean, attributes, s_centroided_);
00693         if (boolean == "true" || boolean == "1")
00694         {
00695           data_processing_.back().getProcessingActions().insert(DataProcessing::PEAK_PICKING);
00696         }
00697       }
00698       else if (tag == "nameValue")
00699       {
00700         String name = "";
00701         optionalAttributeAsString_(name, attributes, s_name_);
00702         if (name == "")
00703           return;
00704 
00705         String value = "";
00706         optionalAttributeAsString_(value, attributes, s_value_);
00707 
00708         String & parent_tag = *(open_tags_.end() - 2);
00709 
00710         if (parent_tag == "msInstrument")
00711         {
00712           exp_->getInstrument().setMetaValue(name, value);
00713         }
00714         else if (parent_tag == "scan")
00715         {
00716           exp_->back().setMetaValue(name, value);
00717         }
00718         else
00719         {
00720           std::cout << " Warning: Unexpected tag 'nameValue' in tag '" << parent_tag << "'" << "\n";
00721         }
00722       }
00723       else if (tag == "processingOperation")
00724       {
00725         String name = "";
00726         optionalAttributeAsString_(name, attributes, s_name_);
00727         if (name == "")
00728           return;
00729 
00730         String value = "";
00731         optionalAttributeAsString_(value, attributes, s_value_);
00732 
00733         data_processing_.back().setMetaValue(name, value);
00734       }
00735 
00736       //std::cout << " -- !Start -- " << "\n";
00737     }
00738 
00739     template <typename MapType>
00740     void MzXMLHandler<MapType>::endElement(const XMLCh * const /*uri*/, const XMLCh * const /*local_name*/, const XMLCh * const qname)
00741     {
00742       //std::cout << " -- End -- " << sm_.convert(qname) << " -- " << "\n";
00743 
00744       static const XMLCh * s_mzxml = xercesc::XMLString::transcode("mzXML");
00745       static const XMLCh * s_peaks = xercesc::XMLString::transcode("peaks");
00746 
00747       open_tags_.pop_back();
00748 
00749       //abort if this scan should be skipped
00750       if (skip_spectrum_)
00751         return;
00752 
00753       if (equal_(qname, s_mzxml))
00754       {
00755         logger_.endProgress();
00756       }
00757       else if (equal_(qname, s_peaks))
00758       {
00759         //std::cout << "reading scan" << "\n";
00760         if (char_rest_ == "")       // no peaks
00761         {
00762           return;
00763         }
00764 
00765         //remove whitespaces from binary data
00766         //this should not be necessary, but linebreaks inside the base64 data are unfortunately no exception
00767         char_rest_.removeWhitespaces();
00768 
00769         if (precision_ == "64")
00770         {
00771           std::vector<DoubleReal> data;
00772           if (compressionType_ == "zlib")
00773           {
00774             decoder_.decode(char_rest_, Base64::BYTEORDER_BIGENDIAN, data, true);
00775           }
00776           else
00777           {
00778             decoder_.decode(char_rest_, Base64::BYTEORDER_BIGENDIAN, data);
00779           }
00780           char_rest_ = "";
00781           PeakType peak;
00782           //push_back the peaks into the container
00783           for (Size n = 0; n < (2 * peak_count_); n += 2)
00784           {
00785             // check if peak in in the specified m/z  and intensity range
00786             if ((!options_.hasMZRange() || options_.getMZRange().encloses(DPosition<1>(data[n])))
00787                && (!options_.hasIntensityRange() || options_.getIntensityRange().encloses(DPosition<1>(data[n + 1]))))
00788             {
00789               peak.setMZ(data[n]);
00790               peak.setIntensity(data[n + 1]);
00791               exp_->back().push_back(peak);
00792             }
00793           }
00794         }
00795         else            //precision 32
00796         {
00797           std::vector<Real> data;
00798           if (compressionType_ == "zlib")
00799           {
00800             decoder_.decode(char_rest_, Base64::BYTEORDER_BIGENDIAN, data, true);
00801           }
00802           else
00803           {
00804             decoder_.decode(char_rest_, Base64::BYTEORDER_BIGENDIAN, data);
00805           }
00806           char_rest_ = "";
00807           PeakType peak;
00808           //push_back the peaks into the container
00809           for (Size n = 0; n < (2 * peak_count_); n += 2)
00810           {
00811             if ((!options_.hasMZRange() || options_.getMZRange().encloses(DPosition<1>(data[n])))
00812                && (!options_.hasIntensityRange() || options_.getIntensityRange().encloses(DPosition<1>(data[n + 1]))))
00813             {
00814               peak.setMZ(data[n]);
00815               peak.setIntensity(data[n + 1]);
00816               exp_->back().push_back(peak);
00817             }
00818           }
00819         }
00820       }
00821       //std::cout << " -- End -- " << "\n";
00822       sm_.clear();
00823     }
00824 
00825     template <typename MapType>
00826     void MzXMLHandler<MapType>::characters(const XMLCh * const chars, const XMLSize_t /*length*/)
00827     {
00828       //Abort if this spectrum should be skipped
00829       if (skip_spectrum_)
00830         return;
00831 
00832       char * transcoded_chars = sm_.convert(chars);
00833 
00834       if (open_tags_.back() == "peaks")
00835       {
00836         //chars may be split to several chunks => concatenate them
00837         char_rest_ += transcoded_chars;
00838       }
00839       else if (open_tags_.back() == "offset" || open_tags_.back() == "indexOffset" || open_tags_.back() == "sha1")
00840       {
00841 
00842       }
00843       else if (open_tags_.back() == "precursorMz")
00844       {
00845         DoubleReal mz_pos = asDouble_(transcoded_chars);
00846         //precursor m/z
00847         exp_->back().getPrecursors().back().setMZ(mz_pos);
00848         //update window bounds - center them around the m/z pos
00849         DoubleReal window_width = exp_->back().getPrecursors().back().getIsolationWindowLowerOffset();
00850         if (window_width != 0.0)
00851         {
00852           exp_->back().getPrecursors().back().setIsolationWindowLowerOffset(mz_pos - 0.5 * window_width);
00853           exp_->back().getPrecursors().back().setIsolationWindowUpperOffset(mz_pos + 0.5 * window_width);
00854         }
00855       }
00856       else if (open_tags_.back() == "comment")
00857       {
00858         String parent_tag = *(open_tags_.end() - 2);
00859         //std::cout << "- Comment of parent " << parent_tag << "\n";
00860 
00861         if (parent_tag == "msInstrument")
00862         {
00863           exp_->getInstrument().setMetaValue("#comment", String(transcoded_chars));
00864         }
00865         else if (parent_tag == "dataProcessing")
00866         {
00867           //this is currently ignored
00868         }
00869         else if (parent_tag == "scan")
00870         {
00871           exp_->back().setComment(transcoded_chars);
00872         }
00873         else if (String(transcoded_chars).trim() != "")
00874         {
00875           warning(LOAD, String("Unhandled comment '") + transcoded_chars + "' in element '" + open_tags_.back() + "'");
00876         }
00877       }
00878       else if (String(transcoded_chars).trim() != "")
00879       {
00880         warning(LOAD, String("Unhandled character content '") + transcoded_chars + "' in element '" + open_tags_.back() + "'");
00881       }
00882     }
00883 
00884     template <typename MapType>
00885     void MzXMLHandler<MapType>::writeTo(std::ostream & os)
00886     {
00887       //determine how many spectra there are (count only those with peaks)
00888       UInt count_tmp_  = 0;
00889       for (Size s = 0; s < cexp_->size(); s++)
00890       {
00891         const SpectrumType & spec = (*cexp_)[s];
00892         if (spec.size() != 0)
00893           ++count_tmp_;
00894       }
00895       if (count_tmp_ == 0)
00896         ++count_tmp_;
00897       logger_.startProgress(0, cexp_->size(), "storing mzXML file");
00898       os << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
00899          << "<mzXML xmlns=\"http://sashimi.sourceforge.net/schema_revision/mzXML_2.1\" "
00900          << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
00901          << "xsi:schemaLocation=\"http://sashimi.sourceforge.net/schema_revision/mzXML_2.1 "
00902          << "http://sashimi.sourceforge.net/schema_revision/mzXML_2.1/mzXML_idx_2.1.xsd\">\n"
00903          << "\t<msRun scanCount=\"" << count_tmp_ << "\">\n";
00904 
00905       //----------------------------------------------------------------------------------------
00906       // parent files
00907       //----------------------------------------------------------------------------------------
00908       if (cexp_->getSourceFiles().empty())
00909       {
00910         os << "\t\t<parentFile fileName=\"\" fileType=\"processedData\" fileSha1=\"0000000000000000000000000000000000000000\"/>\n";
00911       }
00912       else
00913       {
00914         for (Size i = 0; i < cexp_->getSourceFiles().size(); ++i)
00915         {
00916           const SourceFile & sf = cexp_->getSourceFiles()[i];
00917           os << "\t\t<parentFile fileName=\"" << sf.getNameOfFile() << "\" fileType=\"";
00918           //file type is an enum in mzXML => search for 'raw' string
00919           String tmp_string = sf.getFileType();
00920           tmp_string.toLower();
00921           if (tmp_string.hasSubstring("raw"))
00922           {
00923             os << "RAWData";
00924           }
00925           else
00926           {
00927             os << "processedData";
00928           }
00929           //Sha1 checksum must have 40 characters => create a fake if it is unknown
00930           os << "\" fileSha1=\"";
00931           tmp_string = sf.getChecksum();
00932           if (sf.getChecksum().size() != 40 || sf.getChecksumType() != SourceFile::SHA1)
00933           {
00934             os << "0000000000000000000000000000000000000000";
00935           }
00936           else
00937           {
00938             os << sf.getChecksum();
00939           }
00940           os << "\"/>\n";
00941         }
00942       }
00943 
00944       //----------------------------------------------------------------------------------------
00945       //instrument
00946       //----------------------------------------------------------------------------------------
00947       if (cexp_->getInstrument() != Instrument() || cexp_->getContacts().size() != 0)
00948       {
00949         const Instrument & inst = cexp_->getInstrument();
00950         os << "\t\t<msInstrument>\n"
00951            << "\t\t\t<msManufacturer category=\"msManufacturer\" value=\"" << inst.getVendor() << "\"/>\n" << "\t\t\t<msModel category=\"msModel\" value=\"" << inst.getModel() << "\"/>\n";
00952         if (inst.getIonSources().empty() || !inst.getIonSources()[0].getIonizationMethod())
00953         {
00954           os << "\t\t\t<msIonisation category=\"msIonisation\" value=\"\"/>\n";
00955         }
00956         else
00957         {
00958           os << "\t\t\t<msIonisation category=\"msIonisation\" value=\"" << cv_terms_[2][inst.getIonSources()[0].getIonizationMethod()] << "\"/>\n";
00959         }
00960         const std::vector<MassAnalyzer> & analyzers = inst.getMassAnalyzers();
00961         if (analyzers.empty() || !analyzers[0].getResolutionMethod())
00962         {
00963           os << "\t\t\t<msMassAnalyzer category=\"msMassAnalyzer\" value=\"\"/>\n";
00964         }
00965         else
00966         {
00967           os << "\t\t\t<msMassAnalyzer category=\"msMassAnalyzer\" value=\"" << cv_terms_[3][analyzers[0].getType()]  << "\"/>\n";
00968         }
00969         if (inst.getIonDetectors().empty() || !inst.getIonDetectors()[0].getType())
00970         {
00971           os << "\t\t\t<msDetector category=\"msDetector\" value=\"\"/>\n";
00972         }
00973         else
00974         {
00975           os << "\t\t\t<msDetector category=\"msDetector\" value=\"" << cv_terms_[4][inst.getIonDetectors()[0].getType()] << "\"/>\n";
00976         }
00977         os << "\t\t\t<software type=\"acquisition\" name=\"" << inst.getSoftware().getName() << "\" version=\"" << inst.getSoftware().getVersion() << "\"/>\n";
00978         if (analyzers.empty() || !analyzers[0].getResolutionMethod())
00979         {
00980           os << "\t\t\t<msResolution category=\"msResolution\" value=\"\"/>\n";
00981         }
00982         else
00983         {
00984           os << "\t\t\t<msResolution category=\"msResolution\" value=\"" << cv_terms_[5][analyzers[0].getResolutionMethod()] << "\"/>\n";
00985         }
00986 
00987         if (cexp_->getContacts().size() > 0)
00988         {
00989           const ContactPerson & cont = cexp_->getContacts()[0];
00990 
00991           os << "\t\t\t<operator first=\"" << cont.getFirstName() << "\" last=\"" << cont.getLastName() <<  "\"";
00992 
00993           if (cont.getEmail() != "")
00994           {
00995             os << " email=\"" << cont.getEmail() << "\"";
00996           }
00997 
00998           if (cont.getURL() != "")
00999           {
01000             os << " URI=\"" << cont.getURL() << "\"";
01001           }
01002 
01003           if (cont.metaValueExists("#phone"))
01004           {
01005             os << " phone=\"" << (String)(cont.getMetaValue("#phone")) << "\"";
01006           }
01007 
01008           os << "/>\n";
01009         }
01010         writeUserParam_(os, inst, 3);
01011 
01012         if (inst.metaValueExists("#comment"))
01013         {
01014           os << "\t\t\t<comment>" << inst.getMetaValue("#comment") << "</comment>\n";
01015         }
01016 
01017         os << "\t\t</msInstrument>\n";
01018       }
01019 
01020       //----------------------------------------------------------------------------------------
01021       //data processing (the information of the first spectrum is assigned to the whole file)
01022       //----------------------------------------------------------------------------------------
01023       if (cexp_->size() == 0 || (*cexp_)[0].getDataProcessing().empty())
01024       {
01025         os << "\t\t<dataProcessing>\n"
01026            << "\t\t\t<software type=\"processing\" name=\"\" version=\"\"/>\n"
01027            << "\t\t</dataProcessing>\n";
01028       }
01029       else
01030       {
01031         for (Size i = 0; i < (*cexp_)[0].getDataProcessing().size(); ++i)
01032         {
01033           const DataProcessing & data_processing = (*cexp_)[0].getDataProcessing()[i];
01034           os << "\t\t<dataProcessing deisotoped=\""
01035              << data_processing.getProcessingActions().count(DataProcessing::DEISOTOPING)
01036              << "\" chargeDeconvoluted=\""
01037              << data_processing.getProcessingActions().count(DataProcessing::CHARGE_DECONVOLUTION)
01038              << "\" centroided=\""
01039              << data_processing.getProcessingActions().count(DataProcessing::PEAK_PICKING)
01040              << "\"";
01041           if (data_processing.metaValueExists("#intensity_cutoff"))
01042           {
01043             os << " intensityCutoff=\"" << data_processing.getMetaValue("#intensity_cutoff").toString() << "\"";
01044           }
01045           os << ">\n"
01046              << "\t\t\t<software type=\"";
01047           if (data_processing.metaValueExists("#type"))
01048           {
01049             os << data_processing.getMetaValue("#type").toString();
01050           }
01051           else
01052           {
01053             os << "processing";
01054           }
01055 
01056           os << "\" name=\"" << data_processing.getSoftware().getName()
01057              << "\" version=\"" << data_processing.getSoftware().getVersion();
01058 
01059           if (data_processing.getCompletionTime() != DateTime())
01060           {
01061             os << "\" completionTime=\"" << data_processing.getCompletionTime().get().substitute(' ', 'T');
01062           }
01063           os << "\"/>\n";
01064           writeUserParam_(os, data_processing, 3, "processingOperation");
01065 
01066           os << "\t\t</dataProcessing>\n";
01067         }
01068       }
01069 
01070       //check if the nativeID of all spectra are numbers or numbers prefixed with 'scan='
01071       //If not we need to renumber all spectra.
01072       bool all_numbers = true;
01073       bool all_empty = true;
01074       bool all_prefixed_numbers = true;
01075       for (Size s = 0; s < cexp_->size(); s++)
01076       {
01077         String native_id = (*cexp_)[s].getNativeID();
01078         if (!native_id.hasPrefix("scan="))
01079         {
01080           all_prefixed_numbers = false;
01081         }
01082         else
01083         {
01084           native_id = native_id.substr(5);
01085         }
01086         try
01087         {
01088           native_id.toInt();
01089         }
01090         catch (Exception::ConversionError &)
01091         {
01092           all_numbers = false;
01093           all_prefixed_numbers = false;
01094           if (native_id != "")
01095           {
01096             all_empty = false;
01097           }
01098         }
01099       }
01100       //If we need to renumber and the nativeIDs were not empty, warn the user
01101       if (!all_numbers && !all_empty)
01102       {
01103         warning(STORE, "Not all spectrum native IDs are numbers or correctly prefixed with 'scan='. The spectra are renumbered and the native IDs are lost!");
01104       }
01105 
01106       // write scans
01107       std::stack<UInt> open_scans;
01108       for (Size s = 0; s < cexp_->size(); s++)
01109       {
01110         logger_.setProgress(s);
01111         const SpectrumType & spec = (*cexp_)[s];
01112 
01113         UInt ms_level = spec.getMSLevel();
01114         open_scans.push(ms_level);
01115 
01116         Size spectrum_id = s + 1;
01117         if (all_prefixed_numbers)
01118         {
01119           spectrum_id = spec.getNativeID().substr(5).toInt();
01120         }
01121         else if (all_numbers)
01122         {
01123           spectrum_id = spec.getNativeID().toInt();
01124         }
01125 
01126         os << String(ms_level + 1, '\t')
01127            << "<scan num=\"" << spectrum_id << "\" msLevel=\""
01128            << ms_level << "\" peaksCount=\""
01129            << spec.size() << "\" polarity=\"";
01130         if (spec.getInstrumentSettings().getPolarity() == IonSource::POSITIVE)
01131         {
01132           os << "+";
01133         }
01134         else if (spec.getInstrumentSettings().getPolarity() == IonSource::NEGATIVE)
01135         {
01136           os << "-";
01137         }
01138         else
01139         {
01140           os << "any";
01141         }
01142 
01143         //scan type
01144         switch (spec.getInstrumentSettings().getScanMode())
01145         {
01146         case InstrumentSettings::UNKNOWN:
01147           break;
01148 
01149         case InstrumentSettings::MASSSPECTRUM:
01150         case InstrumentSettings::MS1SPECTRUM:
01151         case InstrumentSettings::MSNSPECTRUM:
01152           if (spec.getInstrumentSettings().getZoomScan())
01153           {
01154             os << "\" scanType=\"zoom";
01155           }
01156           else
01157           {
01158             os << "\" scanType=\"Full";
01159           }
01160           break;
01161 
01162         case InstrumentSettings::SIM:
01163           os << "\" scanType=\"SIM";
01164           break;
01165 
01166         case InstrumentSettings::SRM:
01167           os << "\" scanType=\"SRM";
01168           break;
01169 
01170         case InstrumentSettings::CRM:
01171           os << "\" scanType=\"CRM";
01172           break;
01173 
01174         default:
01175           os << "\" scanType=\"Full";
01176           warning(STORE, String("Scan type '") + InstrumentSettings::NamesOfScanMode[spec.getInstrumentSettings().getScanMode()] + "' not supported by mzXML. Using 'Full' scan mode!");
01177         }
01178 
01179         os << "\" retentionTime=\"";
01180         if (spec.getRT() < 0)
01181           os << "-";
01182         os << "PT" << std::fabs(spec.getRT()) << "S\"";
01183         if (!spec.getInstrumentSettings().getScanWindows().empty())
01184         {
01185           os << " startMz=\"" << spec.getInstrumentSettings().getScanWindows()[0].begin << "\" endMz=\"" << spec.getInstrumentSettings().getScanWindows()[0].end << "\"";
01186         }
01187         if (spec.getInstrumentSettings().getScanWindows().size() > 1)
01188         {
01189           warning(STORE, "The MzXML format can store only one scan window for each scan. Only the first one is stored!");
01190         }
01191         os << ">\n";
01192 
01193 
01194         for (Size i = 0; i < spec.getPrecursors().size(); ++i)
01195         {
01196           const Precursor & precursor = spec.getPrecursors()[i];
01197           //intensity
01198           os << String(ms_level + 2, '\t') << "<precursorMz precursorIntensity=\"" << precursor.getIntensity();
01199           //charge
01200           if (precursor.getCharge() != 0)
01201             os << "\" precursorCharge=\"" << precursor.getCharge();
01202           //window size
01203           if (precursor.getIsolationWindowLowerOffset() != precursor.getIsolationWindowUpperOffset())
01204             os << "\" windowWideness=\"" << (precursor.getIsolationWindowUpperOffset() - precursor.getIsolationWindowLowerOffset());
01205           //m/z
01206           os << "\">" << precursor.getMZ() << "</precursorMz>\n";
01207         }
01208 
01209         if (!spec.empty())
01210         {
01211           os << String(ms_level + 2, '\t') << "<peaks precision=\"32\"" << " byteOrder=\"network\" pairOrder=\"m/z-int\">";
01212 
01213           //std::cout << "Writing scan " << s << "\n";
01214           std::vector<Real> tmp;
01215           for (Size i = 0; i < spec.size(); i++)
01216           {
01217             tmp.push_back(spec[i].getMZ());
01218             tmp.push_back(spec[i].getIntensity());
01219           }
01220 
01221           String encoded;
01222           decoder_.encode(tmp, Base64::BYTEORDER_BIGENDIAN, encoded);
01223           os << encoded << "</peaks>\n";
01224         }
01225         else
01226         {
01227           os << String(ms_level + 2, '\t') << "<peaks precision=\"32\"" << " byteOrder=\"network\" pairOrder=\"m/z-int\" xsi:nil=\"1\"/>\n";
01228         }
01229 
01230         writeUserParam_(os, spec, ms_level + 2);
01231         if (spec.getComment() != "")
01232         {
01233           os << String(ms_level + 2, '\t') << "<comment>" << spec.getComment() << "</comment>\n";
01234         }
01235 
01236         //check MS level of next scan and close scans (scans can be nested)
01237         UInt next_ms_level = 0;
01238         if (s < cexp_->size() - 1)
01239         {
01240           next_ms_level = ((*cexp_)[s + 1]).getMSLevel();
01241         }
01242         //std::cout << "scan: " << s << " this: " << ms_level << " next: " << next_ms_level << "\n";
01243         if (next_ms_level <= ms_level)
01244         {
01245           for (Size i = 0; i <= ms_level - next_ms_level && !open_scans.empty(); ++i)
01246           {
01247             os << String(ms_level - i + 1, '\t') << "</scan>\n";
01248             open_scans.pop();
01249           }
01250         }
01251       }
01252 
01253       os << "\t</msRun>\n"
01254          << "\t<indexOffset>0</indexOffset>\n"
01255          << "</mzXML>\n";
01256 
01257       logger_.endProgress();
01258       spec_write_counter_ = 1;
01259     }
01260 
01261   }   // namespace Internal
01262 
01263 } // namespace OpenMS
01264 
01265 #endif

OpenMS / TOPP release 1.10.0 Documentation generated on Thu Mar 7 2013 09:42:43 using doxygen 1.7.1