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 {
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 ∈
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 }
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
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 }