Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-01 07:54:56

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 
0014 // Framework include files
0015 #include <XML/Printout.h>
0016 #include <XML/UriReader.h>
0017 #include <XML/DocumentHandler.h>
0018 
0019 // C/C++ include files
0020 #include <memory>
0021 #include <iostream>
0022 #include <sys/types.h>
0023 #include <sys/stat.h>
0024 #ifndef _WIN32
0025 #include <libgen.h>
0026 #endif
0027 #include <TSystem.h>
0028 
0029 using namespace dd4hep::xml;
0030 
0031 namespace {
0032   std::string undressed_file_name(const std::string& fn)   {
0033     if ( !fn.empty() )   {
0034       TString tfn(fn);
0035       gSystem->ExpandPathName(tfn);
0036       return std::string(tfn.Data());
0037     }
0038     return fn;
0039   }
0040   int s_minPrintLevel = dd4hep::INFO;
0041 
0042   std::string _clean_fname(const std::string& filepath) {
0043     // This function seems to resolve environment variables inside the filepath string and return resolved string
0044     std::string const& temp = getEnviron(filepath);
0045     std::string temp2 = undressed_file_name( temp.empty() ? filepath : temp );
0046     if ( strncmp(temp2.c_str(),"file:",5)==0 ) return temp2.substr(5);
0047     return temp2;
0048   }
0049 
0050 }
0051 
0052 #ifndef __TIXML__
0053 #include <xercesc/framework/LocalFileFormatTarget.hpp>
0054 #include <xercesc/framework/StdOutFormatTarget.hpp>
0055 #include <xercesc/framework/MemBufFormatTarget.hpp>
0056 #include <xercesc/framework/MemBufInputSource.hpp>
0057 #include <xercesc/sax/SAXParseException.hpp>
0058 #include <xercesc/sax/EntityResolver.hpp>
0059 #include <xercesc/sax/InputSource.hpp>
0060 #include <xercesc/parsers/XercesDOMParser.hpp>
0061 #include <xercesc/util/XMLEntityResolver.hpp>
0062 #include <xercesc/util/PlatformUtils.hpp>
0063 #include <xercesc/util/XercesDefs.hpp>
0064 #include <xercesc/util/XMLUni.hpp>
0065 #include <xercesc/util/XMLURL.hpp>
0066 #include <xercesc/util/XMLString.hpp>
0067 #include <xercesc/dom/DOM.hpp>
0068 #include <xercesc/sax/ErrorHandler.hpp>
0069 
0070 using namespace xercesc;
0071 
0072 /// Namespace for the AIDA detector description toolkit
0073 namespace dd4hep {
0074 
0075   /// Namespace containing utilities to parse XML files using XercesC or TinyXML
0076   namespace xml {
0077 
0078     /// XML-DOM ERror handler class for the XercesC document parser.
0079     class DocumentErrorHandler: public ErrorHandler, public DOMErrorHandler {
0080     public:
0081       /// Constructor
0082       DocumentErrorHandler() {
0083       }
0084       /// Destructor
0085       virtual ~DocumentErrorHandler()  {
0086         printout(DEBUG,"DocumentErrorHandler","+++ Destructing the XercesC DOM-XML document error handler....");
0087       }
0088       /// Reset errors (Noop)
0089       void resetErrors() {
0090       }
0091       /// Warnings callback. Ignore them
0092       void warning(const SAXParseException& /* e */) {
0093       }
0094       /// Error handler
0095       void error(const SAXParseException& e);
0096       /// Fatal error handler
0097       void fatalError(const SAXParseException& e);
0098       /// Dom Error handler callback
0099       virtual bool handleError(const DOMError& domError);
0100     };
0101 
0102     /// Dom Error handler callback
0103     bool DocumentErrorHandler::handleError(const DOMError& domError) {
0104       std::string err = "DOM UNKNOWN: ";
0105       switch (domError.getSeverity()) {
0106       case DOMError::DOM_SEVERITY_WARNING:
0107         err = "DOM WARNING: ";
0108         break;
0109       case DOMError::DOM_SEVERITY_ERROR:
0110         err = "DOM ERROR:   ";
0111         break;
0112       case DOMError::DOM_SEVERITY_FATAL_ERROR:
0113         err = "DOM FATAL:   ";
0114         break;
0115       default:
0116         return false;
0117       }
0118       printout(FATAL,"DocumentErrorHandler", "+++ %s %s: %s", err.c_str(),
0119                _toString(domError.getType()).c_str(),_toString(domError.getMessage()).c_str());
0120       DOMLocator* loc = domError.getLocation();
0121       if (loc) {
0122         printout(FATAL,"DocumentErrorHandler","+++ Location: Line:%d Column: %d",
0123                  int(loc->getLineNumber()),int(loc->getColumnNumber()));
0124       }
0125       return false;
0126     }
0127     /// Error handler
0128     void DocumentErrorHandler::error(const SAXParseException& e) {
0129       std::string m(_toString(e.getMessage()));
0130       if (m.find("The values for attribute 'name' must be names or name tokens") != std::string::npos
0131           || m.find("The values for attribute 'ID' must be names or name tokens") != std::string::npos
0132           || m.find("for attribute 'name' must be Name or Nmtoken") != std::string::npos
0133           || m.find("for attribute 'ID' must be Name or Nmtoken") != std::string::npos
0134           || m.find("for attribute 'name' is invalid Name or NMTOKEN value") != std::string::npos
0135           || m.find("for attribute 'ID' is invalid Name or NMTOKEN value") != std::string::npos)
0136         return;
0137       std::string sys(_toString(e.getSystemId()));
0138       printout(ERROR,"XercesC","+++ Error at file \"%s\", Line %d Column: %d Message:%s",
0139                sys.c_str(), int(e.getLineNumber()), int(e.getColumnNumber()), m.c_str());
0140     }
0141     /// Fatal error handler
0142     void DocumentErrorHandler::fatalError(const SAXParseException& e) {
0143       std::string m(_toString(e.getMessage()));
0144       std::string sys(_toString(e.getSystemId()));
0145       printout(FATAL,"XercesC","+++ FATAL Error at file \"%s\", Line %d Column: %d Message:%s",
0146                sys.c_str(), int(e.getLineNumber()), int(e.getColumnNumber()), m.c_str());
0147     }
0148 
0149     namespace {
0150 
0151       /// Specialized DOM parser to handle special system IDs
0152       class dd4hepDOMParser : public XercesDOMParser      {
0153         /// Pointer to URI reader
0154         UriReader*           m_reader;
0155         /// Xerces Error handler
0156         DocumentErrorHandler m_errHandle_tr;
0157         class Resolver : public XMLEntityResolver {
0158           dd4hepDOMParser* parser;
0159         public:
0160           Resolver(dd4hepDOMParser* p) : parser(p) {}
0161           virtual ~Resolver() {}
0162           virtual InputSource *resolveEntity(XMLResourceIdentifier *id)
0163           {   return parser->read_uri(id);                            }
0164         };
0165         Resolver m_resolver;
0166       public:
0167         /// Initializing constructor
0168         dd4hepDOMParser(UriReader* rdr) : XercesDOMParser(), m_reader(rdr), m_resolver(this)  {
0169           //printout(FATAL,"XercesC","+++ Creating new parser");
0170           setErrorHandler(&m_errHandle_tr);
0171           setXMLEntityResolver(&m_resolver);
0172         }
0173         /// Default destructor
0174         virtual ~dd4hepDOMParser() {
0175           //printout(FATAL,"XercesC","+++ Deleting new parser");
0176         }
0177         /// Entity resolver overload to use uri reader
0178         InputSource *read_uri(XMLResourceIdentifier *id)   {
0179           if ( m_reader )   {
0180             std::string buf, systemID(_toString(id->getSystemId()));
0181             if ( m_reader->load(systemID, buf) )  {
0182               const XMLByte* input = (const XMLByte*)XMLString::replicate(buf.c_str());
0183 #if 0
0184               std::string baseURI(_toString(id->getBaseURI()));
0185               std::string schema(_toString(id->getSchemaLocation()));
0186               std::string ns(_toString(id->getNameSpace()));
0187               if ( s_minPrintLevel <= INFO ) {
0188                 printout(INFO,"XercesC","+++ Resolved URI: sysID:%s uri:%s ns:%s schema:%s",
0189                          systemID.c_str(), baseURI.c_str(), ns.c_str(), schema.c_str());
0190               }
0191 #endif
0192               return new MemBufInputSource(input,buf.length(),systemID.c_str(),true);
0193             }
0194           }
0195           return 0;
0196         }
0197       };
0198 
0199       /// Helper function to create a XercesC pareser
0200       XercesDOMParser* make_parser(UriReader* reader=0) {
0201         XercesDOMParser* parser = new dd4hepDOMParser(reader);
0202         parser->setValidationScheme(XercesDOMParser::Val_Auto);
0203         parser->setValidationSchemaFullChecking(true);
0204         parser->setCreateEntityReferenceNodes(false);
0205         parser->setDoNamespaces(false);
0206         parser->setDoSchema(true);
0207 
0208         ////parser->setDoNamespaces( true );
0209         //domParser->setDoSchema( true );
0210         ////parser->setHandleMultipleImports ( true );
0211         //domParser->setValidationSchemaFullChecking( true );
0212         return parser;
0213       }
0214     }
0215 
0216     /// Dump DOM tree using XercesC handles
0217     void dumpTree(DOMNode* doc, std::ostream& os) {
0218       if ( doc )  {
0219         DOMImplementation  *imp = DOMImplementationRegistry::getDOMImplementation(Strng_t("LS"));
0220         MemBufFormatTarget *tar = new MemBufFormatTarget();
0221         DOMLSOutput        *out = imp->createLSOutput();
0222         DOMLSSerializer    *wrt = imp->createLSSerializer();
0223         out->setByteStream(tar);
0224         wrt->getDomConfig()->setParameter(Strng_t("format-pretty-print"), true);
0225         wrt->write(doc, out);
0226         os << tar->getRawBuffer() << std::endl << std::flush;
0227         out->release();
0228         wrt->release();
0229         return;
0230       }
0231       printout(ERROR,"dumpTree","+++ Cannot dump invalid document.");
0232     }
0233 
0234     /// Dump DOM tree using XercesC handles
0235     void dump_doc(DOMDocument* doc, std::ostream& os) {
0236       dumpTree(doc,os);
0237     }
0238     /// Dump DOM tree using XercesC handles
0239     void dump_tree(Handle_t elt, std::ostream& os) {
0240       dumpTree((DOMNode*)elt.ptr(),os);
0241     }
0242     /// Dump DOM tree using XercesC handles
0243     void dump_tree(Document doc, std::ostream& os) {
0244       dump_doc((DOMDocument*)doc.ptr(),os);
0245     }
0246   }
0247 }
0248 
0249 #ifdef DD4HEP_NONE
0250 /// System ID of a given XML entity
0251 std::string DocumentHandler::system_path(Handle_t base, const std::string& fn)   {
0252   std::string path = system_path(base);
0253   std::string dir  = ::dirname((char*)path.c_str());
0254   return dir+fn;
0255 }
0256 #else
0257 
0258 #include <TUri.h>
0259 #include <TUrl.h>
0260 #endif
0261 
0262 /// System ID of a given XML entity
0263 std::string DocumentHandler::system_path(Handle_t base, const std::string& fn)   {
0264   std::string path, dir = system_path(base);
0265   TUri uri_base(dir.c_str()), uri_rel(fn.c_str());
0266   TUrl url_base(dir.c_str());
0267   path = TUri::MergePaths(uri_rel,uri_base);
0268   TUri final(path.c_str());
0269   final.Normalise();
0270   path = url_base.GetProtocol()+std::string("://")+final.GetUri().Data();
0271   if ( path[path.length()-1]=='/' ) path = path.substr(0,path.length()-1);
0272   return path;
0273 }
0274 
0275 /// System ID of a given XML entity
0276 std::string DocumentHandler::system_path(Handle_t base)   {
0277   DOMElement* elt = (DOMElement*)base.ptr();
0278   std::string path = _toString(elt->getBaseURI());
0279   if ( path[0] == '/' )  {
0280     std::string tmp = "file:"+path;
0281     return tmp;
0282   }
0283   return path;
0284 }
0285 
0286 /// Load secondary XML file with relative addressing with respect to handle
0287 Document DocumentHandler::load(Handle_t base, const XMLCh* fname, UriReader* reader) const {
0288   std::string path;
0289   DOMElement* elt = (DOMElement*)base.ptr();
0290   try  {
0291     Document doc;
0292     Strng_t p = _toString(fname);    
0293     path      = _toString(fname);
0294     /// This is a bit complicated, but if the primary source is in-memory
0295     try  {
0296       XMLURL  ref_url(elt->getBaseURI(), p);
0297       path = _toString(ref_url.getURLText());
0298     }
0299     catch(...)   {
0300     }
0301     return load(path, reader);
0302   }
0303   catch(const std::exception& exc)   {
0304     std::string b = _toString(elt->getBaseURI());
0305     std::string e = _toString(fname);
0306     printout(DEBUG,"DocumentHandler","+++ URI exception: %s -> %s [%s]",b.c_str(),e.c_str(),exc.what());
0307   }
0308   catch(...)   {
0309     std::string b = _toString(elt->getBaseURI());
0310     std::string e = _toString(fname);
0311     printout(DEBUG,"DocumentHandler","+++ URI exception: %s -> %s",b.c_str(),e.c_str());
0312   }
0313   if ( reader )   {
0314     std::string buf, sys = system_path(base,fname);
0315 #if 0
0316     std::string buf, sys, dir = _toString(elt->getBaseURI());
0317     std::string fn = _toString(fname);
0318     dir = ::dirname((char*)dir.c_str());
0319     while( fn.substr(0,3) == "../" )  {
0320       dir = ::dirname((char*)dir.c_str());
0321       fn = fn.substr(3);
0322     }
0323     sys = dir + "/" + fn;
0324 #endif
0325     if ( reader->load(sys, buf) )  {
0326 #if 0
0327       Document doc = parse(buf.c_str(), buf.length(), sys.c_str(), reader);
0328       dumpTree(doc);
0329       return doc;
0330 #endif
0331       return parse(buf.c_str(), buf.length(), sys.c_str(), reader);
0332     }
0333   }
0334   return Document(0);
0335 }
0336 
0337 /// Load XML file and parse it using URI resolver to read data.
0338 Document DocumentHandler::load(const std::string& fname, UriReader* reader) const   {
0339   auto fname_clean = _clean_fname(fname);
0340   std::string path;
0341   printout(DEBUG,"DocumentHandler","+++ Loading document URI: %s",fname_clean.c_str());
0342   try  {
0343     size_t idx = fname_clean.find(':');
0344     size_t idq = fname_clean.find('/');
0345     if ( idq == std::string::npos ) idq = 0;
0346     XMLURL xerurl = (const XMLCh*) Strng_t(idx==std::string::npos || idx>idq ? "file:"+fname_clean : fname_clean);
0347     std::string proto  = _toString(xerurl.getProtocolName());
0348     path = _toString(xerurl.getPath());
0349     printout(DEBUG,"DocumentHandler","+++             protocol:%s path:%s",proto.c_str(), path.c_str());
0350   }
0351   catch(...)   {
0352   }
0353   std::unique_ptr < XercesDOMParser > parser(make_parser(reader));
0354   try {
0355     if ( !path.empty() )  {
0356       parser->parse(path.c_str());
0357       if ( reader ) reader->parserLoaded(path);
0358     }
0359     else   {
0360       if ( reader && reader->load(fname_clean, path) )  {
0361         MemBufInputSource src((const XMLByte*)path.c_str(), path.length(), fname.c_str(), false);
0362         parser->parse(src);
0363         return (XmlDocument*)parser->adoptDocument();
0364       }
0365       return (XmlDocument*)0;
0366     }
0367   }
0368   catch (const std::exception& e) {
0369     printout(ERROR,"DocumentHandler","+++ Exception(XercesC): parse(path):%s",e.what());
0370     try {
0371       parser->parse(fname.c_str());
0372       if ( reader ) reader->parserLoaded(path);
0373     }
0374     catch (const std::exception& ex) {
0375       printout(FATAL,"DocumentHandler","+++ Exception(XercesC): parse(URI):%s",ex.what());
0376       throw;
0377     }
0378   }
0379   printout(DEBUG,"DocumentHandler","+++ Document %s succesfully parsed with XercesC .....",path.c_str());
0380   return (XmlDocument*)parser->adoptDocument();
0381 }
0382 
0383 /// Parse a standalong XML string into a document.
0384 Document DocumentHandler::parse(const char* bytes, size_t length, const char* sys_id, UriReader* rdr) const {
0385   std::unique_ptr < XercesDOMParser > parser(make_parser(rdr));
0386   MemBufInputSource src((const XMLByte*)bytes, length, sys_id, false);
0387   parser->parse(src);
0388   DOMDocument* doc = parser->adoptDocument();
0389   doc->setXmlStandalone(true);
0390   doc->setStrictErrorChecking(true);
0391   return (XmlDocument*) doc;
0392 }
0393 
0394 /// Write xml document to output file (stdout if file name empty)
0395 int DocumentHandler::output(Document doc, const std::string& fname) const {
0396   XMLFormatTarget *tar = 0;
0397   DOMImplementation *imp = DOMImplementationRegistry::getDOMImplementation(Strng_t("LS"));
0398   DOMLSOutput *out = imp->createLSOutput();
0399   DOMLSSerializer *wrt = imp->createLSSerializer();
0400 
0401   if (fname.empty())
0402     tar = new StdOutFormatTarget();
0403   else   {
0404     std::string fn = undressed_file_name(fname);
0405     tar = new LocalFileFormatTarget(Strng_t(fn));
0406   }
0407   out->setByteStream(tar);
0408   wrt->getDomConfig()->setParameter(Strng_t("format-pretty-print"), true);
0409   wrt->write((xercesc::DOMDocument*) doc.ptr(), out);
0410   out->release();
0411   wrt->release();
0412   delete tar;
0413   return 1;
0414 }
0415 
0416 #else
0417 
0418 #include <XML/tinyxml.h>
0419 
0420 /// Namespace for the AIDA detector description toolkit
0421 namespace dd4hep {
0422   /// Namespace containing utilities to parse XML files using XercesC or TinyXML
0423   namespace xml {
0424 
0425     /// XML-DOM ERror handler class for the TinyXML document parser (Compatibility class)
0426     class DocumentErrorHandler {};
0427 
0428     union Xml {
0429       Xml(void* ptr) : p(ptr) {}
0430       Xml(const void* ptr) : cp(ptr) {}
0431       void* p;
0432       const void* cp;
0433       TiXmlElement* e;
0434       XmlElement* xe;
0435       TiXmlAttribute* a;
0436       Attribute attr;
0437       TiXmlNode* n;
0438       TiXmlDocument* d;
0439       XmlDocument* xd;
0440     };
0441   }}
0442 
0443 /// System ID of a given XML entity
0444 std::string DocumentHandler::system_path(Handle_t base, const std::string& fname)   {
0445   std::string fn, clean = _clean_fname(fname);
0446   struct stat st;
0447   Element elt(base);
0448   // Poor man's URI handling. Xerces is much much better here
0449   if ( elt ) {
0450     std::string bn = Xml(elt.document()).d->Value();
0451 #ifdef _WIN32
0452     char drive[_MAX_DRIVE], dir[_MAX_DIR], file[_MAX_FNAME], ext[_MAX_EXT];
0453     ::_splitpath(bn.c_str(),drive,dir,file,ext);
0454     fn = drive;
0455     fn += ":";
0456     fn += dir;
0457     fn += "/";
0458     fn += clean;
0459 #else
0460     fn = ::dirname((char*)bn.c_str());
0461 #endif
0462     fn += "/";
0463     fn += _clean_fname(fname);
0464   }
0465   if ( ::stat(fn.c_str(),&st)==0 )
0466     return fn;
0467   else if ( ::stat(clean.c_str(),&st)==0 )
0468     return clean;
0469   return fname;
0470 }
0471 
0472 /// System ID of a given XML entity
0473 std::string DocumentHandler::system_path(Handle_t base)   {
0474   std::string fn;
0475   Element elt(base);
0476   // Poor man's URI handling. Xerces is much much better here
0477   if ( elt ) {
0478     fn = Xml(elt.document()).d->Value();
0479   }
0480   return undressed_file_name(fn);
0481 }
0482 
0483 /// Load XML file and parse it using URI resolver to read data.
0484 Document DocumentHandler::load(const std::string& fname, UriReader* reader) const  {
0485   std::string clean = _clean_fname(fname);
0486   if ( reader )   {
0487     printout(WARNING,"DocumentHandler","+++ Loading document URI: %s %s",
0488              fname.c_str(),"[URI Resolution is not supported by TiXML]");
0489   }
0490   else if ( s_minPrintLevel <= INFO ) {
0491     printout(INFO,"DocumentHandler","+++ Loading document URI: %s [Resolved:'%s']",
0492              fname.c_str(),clean.c_str());
0493   }
0494   TiXmlDocument* doc = new TiXmlDocument(clean.c_str());
0495   bool result = false;
0496   try {
0497     result = doc->LoadFile();
0498     if ( !result ) {
0499       if ( doc->Error() ) {
0500         printout(FATAL,"DocumentHandler","+++ Error (TinyXML) parsing XML document:%s [%s]",
0501                  fname.c_str(), clean.c_str());
0502         printout(FATAL,"DocumentHandler","+++ Error (TinyXML) XML parsing error:%s",
0503                  doc->ErrorDesc());
0504         printout(FATAL,"DocumentHandler","+++ Document:%s Location Line:%d Column:%d",
0505                  doc->Value(), doc->ErrorRow(), doc->ErrorCol());
0506         except("dd4hep:XML","++ file:%s error:%s",clean.c_str(),doc->ErrorDesc());
0507       }
0508       except("dd4hep:XML","++ Unknown error (TinyXML) while parsing:%s",fname.c_str());
0509     }
0510   }
0511   catch(std::exception& e) {
0512     printout(ERROR,"DocumentHandler","+++ Exception (TinyXML): parse(path):%s",e.what());
0513   }
0514   if ( result ) {
0515     if ( s_minPrintLevel <= INFO ) {
0516       printout(INFO,"DocumentHandler","+++ Document %s succesfully parsed with TinyXML .....",
0517                fname.c_str());
0518     }
0519     return (XmlDocument*)doc;
0520   }
0521   delete doc;
0522   return 0;
0523 }
0524 
0525 /// Load XML file and parse it using URI resolver to read data.
0526 Document DocumentHandler::load(Handle_t base, const XmlChar* fname, UriReader* reader) const  {
0527   std::string path = system_path(base, fname);
0528   return load(path,reader);
0529 }
0530 
0531 /// Parse a standalong XML string into a document.
0532 Document DocumentHandler::parse(const char* bytes, size_t length, const char* /* sys_id */, UriReader* reader) const {
0533   if ( reader )   {
0534     printout(WARNING,"DocumentHandler","+++ Parsing memory document %s",
0535              "[URI Resolution is not supported by TiXML]");
0536   }
0537   TiXmlDocument* doc = new TiXmlDocument();
0538   try  {
0539     if ( bytes )   {
0540       size_t str_len = ::strlen(bytes);
0541       size_t len = length;
0542       // TiXml does not support white spaces at the end. Check and remove.
0543       if ( str_len+1 != len || bytes[str_len] != 0 || ::isspace(bytes[str_len-1]) )   {
0544         std::unique_ptr<char[]> data(new char[len+1]);
0545         char* buff = data.get();
0546         try  {
0547           ::memcpy(buff, bytes, len+1);
0548           buff[len] = 0;
0549           for(size_t i=len-1; i>0 && (buff[i]==0 || ::isspace(buff[i])); --i)
0550             buff[i] = 0;
0551           if ( 0 == doc->Parse(buff) ) {
0552             return (XmlDocument*)doc;
0553           }
0554         }
0555         catch(...)   {
0556         }
0557       }
0558       if ( 0 == doc->Parse(bytes) ) {
0559         return (XmlDocument*)doc;
0560       }
0561       if ( doc->Error() ) {
0562         printout(FATAL,"DocumentHandler",
0563                  "+++ Error (TinyXML) while parsing XML string [%s]",
0564                  doc->ErrorDesc());
0565         printout(FATAL,"DocumentHandler",
0566                  "+++ XML Document error: %s Location Line:%d Column:%d",
0567                  doc->Value(), doc->ErrorRow(), doc->ErrorCol());
0568         throw std::runtime_error(std::string("dd4hep: ")+doc->ErrorDesc());
0569       }
0570       throw std::runtime_error("dd4hep: Unknown error while parsing XML document string with TiXml.");
0571     }
0572     throw std::runtime_error("dd4hep: FAILED to parse invalid document string [NULL] with TiXml.");
0573   }
0574   catch(std::exception& e) {
0575     printout(ERROR,"DocumentHandler","+++ Exception (TinyXML): parse(string):%s",e.what());
0576   }
0577   delete doc;
0578   return 0;
0579 }
0580 
0581 /// Write xml document to output file (stdout if file name empty)
0582 int DocumentHandler::output(Document doc, const std::string& fname) const {
0583   std::string fn = undressed_file_name(fname);
0584   FILE* file = fn.empty() ? stdout : ::fopen(fn.c_str(),"w");
0585   if ( !file ) {
0586     printout(ERROR,"DocumentHandler","+++ Failed to open output file: %s",fname.c_str());
0587     return 0;
0588   }
0589   TiXmlDocument* d = (TiXmlDocument*)doc.ptr();
0590   d->Print(file);
0591   if ( !fn.empty() ) ::fclose(file);
0592   return 1;
0593 }
0594 
0595 /// Dump partial or full XML trees
0596 void dd4hep::xml::dump_tree(Handle_t elt, std::ostream& os) {
0597   TiXmlNode* node = (TiXmlNode*)elt.ptr();
0598   TiXmlPrinter printer;
0599   printer.SetStreamPrinting();
0600   node->Accept( &printer );
0601   os << printer.Str();
0602 }
0603 
0604 /// Dump partial or full XML documents
0605 void dd4hep::xml::dump_tree(Document doc, std::ostream& os) {
0606   TiXmlDocument* node = (TiXmlDocument*)doc.ptr();
0607   TiXmlPrinter printer;
0608   printer.SetStreamPrinting();
0609   node->Accept( &printer );
0610   os << printer.Str();
0611 }
0612 #endif
0613 
0614 
0615 /// Default constructor of a document handler using TiXml
0616 DocumentHandler::DocumentHandler() {}
0617 
0618 /// Default destructor of a document handler using TiXml
0619 DocumentHandler::~DocumentHandler() {}
0620 
0621 /// Set minimum print level
0622 int DocumentHandler::setMinimumPrintLevel(int level)    {
0623   int tmp = s_minPrintLevel;
0624   s_minPrintLevel = level;
0625   return tmp;
0626 }
0627 
0628 /// Default comment string
0629 std::string DocumentHandler::defaultComment()  {
0630   const char comment[] = "\n"
0631     "      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
0632     "      ++++   dd4hep generated alignment file using the         ++++\n"
0633     "      ++++   dd4hep Detector description XML generator.        ++++\n"
0634     "      ++++                                                     ++++\n"
0635     "      ++++   Parser:"
0636     XML_IMPLEMENTATION_TYPE
0637     "                ++++\n"
0638     "      ++++                                                     ++++\n"
0639     "      ++++                              M.Frank CERN/LHCb      ++++\n"
0640     "      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n  ";
0641   return comment;
0642 }
0643 
0644 /// Load XML file and parse it.
0645 Document DocumentHandler::load(const std::string& fname) const {
0646   return load(fname, 0);
0647 }
0648 
0649 /// Load secondary XML file with relative addressing with respect to handle
0650 Document DocumentHandler::load(Handle_t base, const XmlChar* fname) const {
0651   return load(base, fname, 0);
0652 }
0653 
0654 /// Parse a standalong XML string into a document.
0655 Document DocumentHandler::parse(const char* bytes, size_t length) const {
0656   return parse(bytes, length, "xml-memory-buffer", 0);
0657 }
0658 
0659 /// System ID of a given XML entity
0660 std::string DocumentHandler::system_path(Handle_t base, const XmlChar* fname)   {
0661   std::string fn = _toString(fname);
0662   return system_path(base, fn);
0663 }
0664 
0665 /// System directory of a given XML entity
0666 std::string DocumentHandler::system_directory(Handle_t base, const XmlChar* fname)   {
0667   std::string path = system_path(base,fname);
0668   std::string dir = ::dirname((char*)path.c_str());
0669   return dir;
0670 }
0671 
0672 /// System directory of a given XML entity
0673 std::string DocumentHandler::system_directory(Handle_t base)   {
0674   std::string path = system_path(base);
0675   std::string dir = ::dirname((char*)path.c_str());
0676   return dir;
0677 }
0678 
0679 /// Create new XML document by parsing empty xml buffer
0680 Document DocumentHandler::create(const char* tag, const char* comment) const {
0681   std::string top(tag);
0682   std::string empty = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
0683   empty += "<" + top + "/>\0\0";
0684   Document doc = parse(empty.c_str(), empty.length() + 1);
0685   if (comment) {
0686     Element top_elt = doc.root();
0687     top_elt.addComment(comment);
0688   }
0689   return doc;
0690 }
0691 
0692 // Create new XML document by parsing empty xml buffer
0693 Document DocumentHandler::create(const std::string& tag, const std::string& comment) const   {
0694   return create(tag.c_str(), comment.c_str());
0695 }
0696 
0697 /// Dump partial or full XML trees to stdout
0698 void dd4hep::xml::dump_tree(Handle_t elt) {
0699   dump_tree(elt,std::cout);
0700 }
0701 
0702 /// Dump partial or full XML documents to stdout
0703 void dd4hep::xml::dump_tree(Document doc) {
0704   dump_tree(doc,std::cout);
0705 }