CMS 3D CMS Logo

CMSSW_4_4_3_patch1/src/PhysicsTools/MVATrainer/src/XMLDocument.cc

Go to the documentation of this file.
00001 #include <assert.h>
00002 #include <iostream>
00003 #include <iomanip>
00004 #include <sstream>
00005 #include <memory>
00006 #include <string>
00007 #include <cstdio>
00008 #include <stdio.h>
00009 #include <ext/stdio_filebuf.h>
00010 
00011 #include <xercesc/util/PlatformUtils.hpp>
00012 #include <xercesc/util/XMLString.hpp>
00013 #include <xercesc/util/XMLUni.hpp>
00014 #include <xercesc/util/BinInputStream.hpp>
00015 #include <xercesc/dom/DOM.hpp>
00016 #include <xercesc/dom/DOMImplementationLS.hpp>
00017 #include <xercesc/dom/DOMWriter.hpp>
00018 #include <xercesc/framework/LocalFileFormatTarget.hpp>
00019 #include <xercesc/parsers/XercesDOMParser.hpp>
00020 #include <xercesc/sax/InputSource.hpp>
00021 #include <xercesc/sax/HandlerBase.hpp>
00022 
00023 
00024 #include "FWCore/Utilities/interface/Exception.h"
00025 
00026 #include "PhysicsTools/MVATrainer/interface/XMLSimpleStr.h"
00027 #include "PhysicsTools/MVATrainer/interface/XMLUniStr.h"
00028 #include "PhysicsTools/MVATrainer/interface/XMLDocument.h"
00029 
00030 XERCES_CPP_NAMESPACE_USE
00031 
00032 unsigned int XMLDocument::XercesPlatform::instances = 0;
00033 
00034 namespace { // anonymous
00035         struct DocReleaser {
00036                 inline DocReleaser(DOMDocument *doc) : doc(doc) {}
00037                 inline ~DocReleaser() { doc->release(); }
00038 
00039                 DOMDocument *doc;
00040         };
00041 
00042         template<typename T>
00043         class XMLInputSourceWrapper :
00044                 public XERCES_CPP_NAMESPACE_QUALIFIER InputSource {
00045             public:
00046                 typedef typename T::Stream_t Stream_t;
00047 
00048                 XMLInputSourceWrapper(std::auto_ptr<Stream_t> &obj) : obj(obj) {}
00049                 virtual ~XMLInputSourceWrapper() {}
00050 
00051                 virtual XERCES_CPP_NAMESPACE_QUALIFIER BinInputStream*
00052                                                         makeStream() const
00053                 { return new T(*obj); }
00054 
00055             private:
00056                 std::auto_ptr<Stream_t> obj;
00057         };
00058 
00059         class STLInputStream :
00060                         public XERCES_CPP_NAMESPACE_QUALIFIER BinInputStream {
00061             public:
00062                 typedef std::istream Stream_t;
00063 
00064                 STLInputStream(std::istream &in) : in(in) {}
00065                 virtual ~STLInputStream() {}
00066 
00067                 virtual unsigned int curPos() const { return pos; }
00068 
00069                 virtual unsigned int readBytes(XMLByte *const buf,
00070                                                const unsigned int size);
00071 
00072             private:
00073                 std::istream    &in;
00074                 unsigned int    pos;
00075         };
00076 
00077         template<int (*close)(FILE*)>
00078         class stdio_istream : public std::istream {
00079             public:
00080                 typedef __gnu_cxx::stdio_filebuf<char>  __filebuf_type;
00081                 typedef stdio_istream<close>            __istream_type;
00082 
00083                 stdio_istream(FILE *file) :
00084                         file_(file), filebuf_(file, std::ios_base::in)
00085                 { this->init(&filebuf_); }
00086 
00087                 ~stdio_istream()
00088                 { close(file_); }
00089 
00090                 __filebuf_type *rdbuf() const
00091                 { return const_cast<__filebuf_type*>(&filebuf_); }
00092 
00093             private:
00094                 FILE            *file_;
00095                 __filebuf_type  filebuf_;
00096         };
00097 
00098         typedef XMLInputSourceWrapper<STLInputStream> STLInputSource;
00099 } // anonymous namespace
00100 
00101 unsigned int STLInputStream::readBytes(XMLByte* const buf,
00102                                        const unsigned int size)
00103 {
00104         char *rawBuf = reinterpret_cast<char*>(buf);
00105         unsigned int bytes = size * sizeof(XMLByte);
00106         in.read(rawBuf, bytes);
00107         unsigned int readBytes = in.gcount();
00108 
00109         if (in.bad())
00110                 throw cms::Exception("XMLDocument")
00111                         << "I/O stream bad in STLInputStream::readBytes()"
00112                         << std::endl;
00113 
00114         unsigned int read = (unsigned int)(readBytes / sizeof(XMLByte));
00115         unsigned int rest = (unsigned int)(readBytes % sizeof(XMLByte));
00116         for(unsigned int i = 1; i <= rest; i++)
00117                 in.putback(rawBuf[readBytes - i]);
00118 
00119         pos += read;
00120         return read;
00121 }
00122 
00123 XMLDocument::XercesPlatform::XercesPlatform()
00124 {
00125         if (!instances++) {
00126                 try {
00127                         XMLPlatformUtils::Initialize();
00128                 } catch(const XMLException &e) {
00129                         throw cms::Exception("XMLDocument")
00130                                 << "XMLPlatformUtils::Initialize failed "
00131                                    "because of: "
00132                                 << XMLSimpleStr(e.getMessage()) << std::endl;
00133                 }
00134         }
00135 }
00136 
00137 XMLDocument::XercesPlatform::~XercesPlatform()
00138 {
00139         if (!--instances)
00140                 XMLPlatformUtils::Terminate();
00141 }
00142 
00143 XMLDocument::XMLDocument(const std::string &fileName, bool write) :
00144         platform(new XercesPlatform()), fileName(fileName),
00145         write(write), impl(0), doc(0), rootNode(0)
00146 {
00147         if (write)
00148                 openForWrite(fileName);
00149         else {
00150                 std::auto_ptr<std::istream> inputStream(
00151                                         new std::ifstream(fileName.c_str()));
00152                 if (!inputStream->good())
00153                         throw cms::Exception("XMLDocument")
00154                                 << "XML input file \"" << fileName << "\" "
00155                                    "could not be opened for reading."
00156                                 << std::endl;
00157                 openForRead(inputStream);
00158         }
00159 }
00160 
00161 XMLDocument::XMLDocument(const std::string &fileName,
00162                          const std::string &command) :
00163         platform(new XercesPlatform()), fileName(fileName),
00164         write(false), impl(0), doc(0), rootNode(0)
00165 {
00166         FILE *file = popen(command.c_str(), "r");
00167         if (!file)
00168                 throw cms::Exception("XMLDocument")
00169                         << "Could not execute XML preprocessing "
00170                            " command \"" << command << "\"."
00171                         << std::endl;
00172 
00173         std::auto_ptr<std::istream> inputStream(
00174                                         new stdio_istream<pclose>(file));
00175         if (!inputStream->good())
00176                 throw cms::Exception("XMLDocument")
00177                         << "XML preprocessing command \"" << fileName
00178                         << "\" stream could not be opened for reading."
00179                         << std::endl;
00180 
00181         openForRead(inputStream);
00182 }
00183 
00184 XMLDocument::~XMLDocument()
00185 {
00186         if (!write)
00187                 return;
00188 
00189         std::auto_ptr<DocReleaser> docReleaser(new DocReleaser(doc));
00190 
00191         std::auto_ptr<DOMWriter> writer(static_cast<DOMImplementationLS*>(
00192                                                 impl)->createDOMWriter());
00193         assert(writer.get());
00194 
00195         writer->setEncoding(XMLUniStr("UTF-8"));
00196         if (writer->canSetFeature(XMLUni::fgDOMWRTDiscardDefaultContent, true))
00197                 writer->setFeature(XMLUni::fgDOMWRTDiscardDefaultContent, true);
00198         if (writer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true))
00199                 writer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true);
00200 
00201         try {
00202                 std::auto_ptr<XMLFormatTarget> target(
00203                                 new LocalFileFormatTarget(fileName.c_str()));
00204 
00205                 writer->writeNode(target.get(), *doc);
00206         } catch(...) {
00207                 std::remove(fileName.c_str());
00208                 throw;
00209         }
00210 }
00211 
00212 void XMLDocument::openForRead(std::auto_ptr<std::istream> &stream)
00213 {
00214         parser.reset(new XercesDOMParser());
00215         parser->setValidationScheme(XercesDOMParser::Val_Auto);
00216         parser->setDoNamespaces(false);
00217         parser->setDoSchema(false);
00218         parser->setValidationSchemaFullChecking(false);
00219 
00220         errHandler.reset(new HandlerBase());
00221         parser->setErrorHandler(errHandler.get());
00222         parser->setCreateEntityReferenceNodes(false);
00223 
00224         inputSource.reset(new STLInputSource(stream));
00225 
00226         try {
00227                 parser->parse(*inputSource);
00228                 if (parser->getErrorCount())
00229                         throw cms::Exception("XMLDocument")
00230                                 << "XML parser reported errors."
00231                                 << std::endl;
00232         } catch(const XMLException &e) {
00233                 throw cms::Exception("XMLDocument")
00234                         << "XML parser reported DOM error no. "
00235                         << (unsigned long)e.getCode()
00236                         << ": " << XMLSimpleStr(e.getMessage()) << "."
00237                         << std::endl;
00238         } catch(const SAXException &e) {
00239                 throw cms::Exception("XMLDocument")
00240                         << "XML parser reported: "
00241                         << XMLSimpleStr(e.getMessage()) << "."
00242                         << std::endl;
00243         }
00244 
00245         doc = parser->getDocument();
00246 
00247         DOMNode *node = doc->getFirstChild();
00248         while(node && node->getNodeType() != DOMNode::ELEMENT_NODE)
00249                 node = node->getNextSibling();
00250 
00251         if (!node)
00252                 throw cms::Exception("XMLDocument")
00253                         << "XML document didn't contain a valid "
00254                         << "root node." << std::endl;
00255 
00256         rootNode = static_cast<DOMElement*>(node);
00257 }
00258 
00259 void XMLDocument::openForWrite(const std::string &fileName)
00260 {
00261         impl = DOMImplementationRegistry::getDOMImplementation(
00262                                                         XMLUniStr("LS"));
00263         assert(impl);
00264 }
00265 
00266 DOMDocument *XMLDocument::createDocument(const std::string &root)
00267 {
00268         if (doc)
00269                 throw cms::Exception("XMLDocument")
00270                         << "Document already exists in createDocument."
00271                         << std::endl;
00272 
00273         doc = impl->createDocument(0, XMLUniStr(root.c_str()), 0);
00274         rootNode = doc->getDocumentElement();
00275 
00276         return doc;
00277 }
00278 
00279 // specialization of read/write method templates for bool
00280 
00281 static bool isBool(std::string value)
00282 {
00283         for(unsigned int i = 0; i < value.size(); i++)
00284                 if (value[i] >= 'A' && value[i] <= 'Z')
00285                         value[i] += 'a' - 'A';
00286 
00287         if (value == "1" || value == "y" || value == "yes" ||
00288             value == "true" || value == "ok")
00289                 return true;
00290 
00291         if (value == "0" || value == "n" || value == "no" || value == "false")
00292                 return false;
00293 
00294         throw cms::Exception("XMLDocument")
00295                 << "Invalid boolean value in XML document" << std::endl;
00296 }
00297 
00298 static const char *makeBool(bool value)
00299 {
00300         return value ? "true" : "false";
00301 }
00302 
00303 bool XMLDocument::hasAttribute(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *elem,
00304                                const char *name)
00305 {
00306         XMLUniStr uniName(name);
00307         return elem->hasAttribute(uniName);
00308 }
00309 
00310 template<>
00311 bool XMLDocument::readAttribute(
00312                         XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *elem,
00313                         const char *name)
00314 {
00315         XMLUniStr uniName(name);
00316         if (!elem->hasAttribute(uniName))
00317                 throw cms::Exception("MVAComputer")
00318                         << "Missing attribute " << name << " in tag "
00319                         << XMLSimpleStr(elem->getNodeName())
00320                         << "." << std::endl;
00321         const XMLCh *attribute = elem->getAttribute(uniName);
00322         return isBool(XMLSimpleStr(attribute));
00323 }
00324 
00325 template<>
00326 bool XMLDocument::readAttribute(
00327                         XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *elem,
00328                         const char *name, const bool &defValue)
00329 {
00330         XMLUniStr uniName(name);
00331         if (!elem->hasAttribute(uniName))
00332                 return defValue;
00333         const XMLCh *attribute = elem->getAttribute(uniName);
00334         return isBool(XMLSimpleStr(attribute));
00335 }
00336 
00337 template<>
00338 void XMLDocument::writeAttribute(
00339                         XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *elem,
00340                         const char *name, const bool &value)
00341 {
00342         elem->setAttribute(XMLUniStr(name), XMLUniStr(makeBool(value)));
00343 }
00344 
00345 template<>
00346 bool XMLDocument::readContent(
00347                         XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *node)
00348 {
00349         const XMLCh *content = node->getTextContent();
00350         return isBool(XMLSimpleStr(content));
00351 }
00352 
00353 template<>
00354 void XMLDocument::writeContent(
00355                         XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *node,
00356                         XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc,
00357                         const bool &value)
00358 {
00359         node->appendChild(doc->createTextNode(XMLUniStr(makeBool(value))));
00360 }