00001 #include <assert.h>
00002 #include <iostream>
00003 #include <iomanip>
00004 #include <sstream>
00005 #include <memory>
00006 #include <string>
00007
00008 #include <xercesc/util/PlatformUtils.hpp>
00009 #include <xercesc/util/XMLString.hpp>
00010 #include <xercesc/util/XMLUni.hpp>
00011 #include <xercesc/dom/DOM.hpp>
00012 #include <xercesc/dom/DOMImplementationLS.hpp>
00013 #include <xercesc/dom/DOMWriter.hpp>
00014 #include <xercesc/framework/LocalFileFormatTarget.hpp>
00015 #include <xercesc/parsers/XercesDOMParser.hpp>
00016 #include <xercesc/sax/HandlerBase.hpp>
00017
00018 #include "FWCore/Utilities/interface/Exception.h"
00019
00020 #include "PhysicsTools/MVATrainer/interface/XMLSimpleStr.h"
00021 #include "PhysicsTools/MVATrainer/interface/XMLUniStr.h"
00022 #include "PhysicsTools/MVATrainer/interface/XMLDocument.h"
00023
00024 XERCES_CPP_NAMESPACE_USE
00025
00026 unsigned int XMLDocument::XercesPlatform::instances = 0;
00027
00028 namespace {
00029 struct DocReleaser {
00030 inline DocReleaser(DOMDocument *doc) : doc(doc) {}
00031 inline ~DocReleaser() { doc->release(); }
00032
00033 DOMDocument *doc;
00034 };
00035 }
00036
00037 XMLDocument::XercesPlatform::XercesPlatform()
00038 {
00039 if (!instances++) {
00040 try {
00041 XMLPlatformUtils::Initialize();
00042 } catch(const XMLException &e) {
00043 throw cms::Exception("XMLDocument")
00044 << "XMLPlatformUtils::Initialize failed "
00045 "because of: "
00046 << XMLSimpleStr(e.getMessage()) << std::endl;
00047 }
00048 }
00049 }
00050
00051 XMLDocument::XercesPlatform::~XercesPlatform()
00052 {
00053 if (!--instances)
00054 XMLPlatformUtils::Terminate();
00055 }
00056
00057 XMLDocument::XMLDocument(const std::string &fileName, bool write) :
00058 platform(new XercesPlatform()), fileName(fileName),
00059 write(write), impl(0), doc(0), rootNode(0)
00060 {
00061 if (write)
00062 openForWrite(fileName);
00063 else
00064 openForRead(fileName);
00065 }
00066
00067 XMLDocument::~XMLDocument()
00068 {
00069 if (!write)
00070 return;
00071
00072 std::auto_ptr<DocReleaser> docReleaser(new DocReleaser(doc));
00073
00074 std::auto_ptr<DOMWriter> writer(static_cast<DOMImplementationLS*>(
00075 impl)->createDOMWriter());
00076 assert(writer.get());
00077
00078 writer->setEncoding(XMLUniStr("UTF-8"));
00079 if (writer->canSetFeature(XMLUni::fgDOMWRTDiscardDefaultContent, true))
00080 writer->setFeature(XMLUni::fgDOMWRTDiscardDefaultContent, true);
00081 if (writer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true))
00082 writer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true);
00083
00084 try {
00085 std::auto_ptr<XMLFormatTarget> target(
00086 new LocalFileFormatTarget(fileName.c_str()));
00087
00088 writer->writeNode(target.get(), *doc);
00089 } catch(...) {
00090 std::remove(fileName.c_str());
00091 throw;
00092 }
00093 }
00094
00095 void XMLDocument::openForRead(const std::string &fileName)
00096 {
00097 parser = std::auto_ptr<XercesDOMParser>(new XercesDOMParser());
00098 parser->setValidationScheme(XercesDOMParser::Val_Auto);
00099 parser->setDoNamespaces(false);
00100 parser->setDoSchema(false);
00101 parser->setValidationSchemaFullChecking(false);
00102
00103 errHandler = std::auto_ptr<HandlerBase>(new HandlerBase());
00104 parser->setErrorHandler(errHandler.operator -> ());
00105 parser->setCreateEntityReferenceNodes(false);
00106
00107 try {
00108 parser->parse(fileName.c_str());
00109 if (parser->getErrorCount())
00110 throw cms::Exception("XMLDocument")
00111 << "XML parser reported errors."
00112 << std::endl;
00113 } catch(const XMLException &e) {
00114 throw cms::Exception("XMLDocument")
00115 << "XML parser reported DOM error no. "
00116 << (unsigned long)e.getCode()
00117 << ": " << XMLSimpleStr(e.getMessage()) << "."
00118 << std::endl;
00119 } catch(const SAXException &e) {
00120 throw cms::Exception("XMLDocument")
00121 << "XML parser reported: "
00122 << XMLSimpleStr(e.getMessage()) << "."
00123 << std::endl;
00124 }
00125
00126 doc = parser->getDocument();
00127
00128 DOMNode *node = doc->getFirstChild();
00129 while(node && node->getNodeType() != DOMNode::ELEMENT_NODE)
00130 node = node->getNextSibling();
00131
00132 if (!node)
00133 throw cms::Exception("XMLDocument")
00134 << "XML document didn't contain a valid "
00135 << "root node." << std::endl;
00136
00137 rootNode = static_cast<DOMElement*>(node);
00138 }
00139
00140 void XMLDocument::openForWrite(const std::string &fileName)
00141 {
00142 impl = DOMImplementationRegistry::getDOMImplementation(
00143 XMLUniStr("LS"));
00144 assert(impl);
00145 }
00146
00147 DOMDocument *XMLDocument::createDocument(const std::string &root)
00148 {
00149 if (doc)
00150 throw cms::Exception("XMLDocument")
00151 << "Document already exists in createDocument."
00152 << std::endl;
00153
00154 doc = impl->createDocument(0, XMLUniStr(root.c_str()), 0);
00155 rootNode = doc->getDocumentElement();
00156
00157 return doc;
00158 }
00159
00160
00161
00162 static bool isBool(std::string value)
00163 {
00164 for(unsigned int i = 0; i < value.size(); i++)
00165 if (value[i] >= 'A' && value[i] <= 'Z')
00166 value[i] += 'a' - 'A';
00167
00168 if (value == "1" || value == "y" || value == "yes" ||
00169 value == "true" || value == "ok")
00170 return true;
00171
00172 if (value == "0" || value == "n" || value == "no" || value == "false")
00173 return false;
00174
00175 throw cms::Exception("XMLDocument")
00176 << "Invalid boolean value in XML document" << std::endl;
00177 }
00178
00179 static const char *makeBool(bool value)
00180 {
00181 return value ? "true" : "false";
00182 }
00183
00184 bool XMLDocument::hasAttribute(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *elem,
00185 const char *name)
00186 {
00187 XMLUniStr uniName(name);
00188 return elem->hasAttribute(uniName);
00189 }
00190
00191 template<>
00192 bool XMLDocument::readAttribute(
00193 XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *elem,
00194 const char *name)
00195 {
00196 XMLUniStr uniName(name);
00197 if (!elem->hasAttribute(uniName))
00198 throw cms::Exception("MVAComputer")
00199 << "Missing attribute " << name << " in tag "
00200 << XMLSimpleStr(elem->getNodeName())
00201 << "." << std::endl;
00202 const XMLCh *attribute = elem->getAttribute(uniName);
00203 return isBool(XMLSimpleStr(attribute));
00204 }
00205
00206 template<>
00207 bool XMLDocument::readAttribute(
00208 XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *elem,
00209 const char *name, const bool &defValue)
00210 {
00211 XMLUniStr uniName(name);
00212 if (!elem->hasAttribute(uniName))
00213 return defValue;
00214 const XMLCh *attribute = elem->getAttribute(uniName);
00215 return isBool(XMLSimpleStr(attribute));
00216 }
00217
00218 template<>
00219 void XMLDocument::writeAttribute(
00220 XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *elem,
00221 const char *name, const bool &value)
00222 {
00223 elem->setAttribute(XMLUniStr(name), XMLUniStr(makeBool(value)));
00224 }
00225
00226 template<>
00227 bool XMLDocument::readContent(
00228 XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *node)
00229 {
00230 const XMLCh *content = node->getTextContent();
00231 return isBool(XMLSimpleStr(content));
00232 }
00233
00234 template<>
00235 void XMLDocument::writeContent(
00236 XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *node,
00237 XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc,
00238 const bool &value)
00239 {
00240 node->appendChild(doc->createTextNode(XMLUniStr(makeBool(value))));
00241 }