#include #include #include #include #include #include "IXmlOdb.hxx" #include #include #include "ICOMETLog.hxx" //____________________________________________________________________________ COMET::IXmlOdb::IXmlOdb(const char*xbuf,Int_t bufLength) //ctor { this->ClearStats(); fOdb = NULL; fParser = new TDOMParser(); fParser->SetValidate(false); // Allocate one more character than the input buffer size on order to // add string terminator zero after final "odb>" char*buf = (char*)malloc(bufLength+1); memcpy(buf, xbuf, bufLength); buf[bufLength] = 0; // Fix up possible problems found in the past. for (Int_t i=0; i"); if (xend) xend[4] = 0; fParser->ParseBuffer(buf,bufLength); free(buf); buf = 0; TXMLDocument* doc = fParser->GetXMLDocument(); if (!doc) { COMETError("COMET::IXmlOdb::IXmlOdb: Malformed ODB dump: cannot get XML document"); this->ReleaseXMLParser(); return; } fOdb = FindNode(doc->GetRootNode(),"odb"); if (!fOdb) { COMETError("COMET::IXmlOdb::IXmlOdb: Malformed ODB dump: cannot find tag"); this->ReleaseXMLParser(); return; } } //____________________________________________________________________________ COMET::IXmlOdb::IXmlOdb(const char* filename) //ctor { this->ClearStats(); fOdb = NULL; fParser = new TDOMParser(); fParser->SetValidate(false); Int_t status = fParser->ParseFile(filename); if (status != 0) { COMETError("COMET::IXmlOdb::IXmlOdb: Failed to parse XML file " << filename << " ParseFile() returned " << status); this->ReleaseXMLParser(); return; } TXMLDocument* doc = fParser->GetXMLDocument(); if (!doc) { COMETError("COMET::IXmlOdb::IXmlOdb: Malformed ODB dump: cannot get XML document"); this->ReleaseXMLParser(); return; } fOdb = FindNode(doc->GetRootNode(),"odb"); if (!fOdb) { COMETError("COMET::IXmlOdb::IXmlOdb: Malformed ODB dump: cannot find tag"); this->ReleaseXMLParser(); return; } } //____________________________________________________________________________ COMET::IXmlOdb::~IXmlOdb() // dtor { this->ReleaseXMLParser(); } //____________________________________________________________________________ void COMET::IXmlOdb::ClearStats() const { fStatsNumDir = 0; fStatsNumKey = 0; fStatsNumKeyArray = 0; fStatsNumText = 0; fStatsNumValue = 0; fStatsNumOther = 0; } //____________________________________________________________________________ void COMET::IXmlOdb::DumpTree(TXMLNode*node, Int_t print_level, Int_t dir_level, std::string node_path) const { // node The top level node from which to start dump. // print_level The print level:- // = 0 Nothing but accumulate fStats* // = 1 Directory structure // = 2 Full structure excluding keyarray values // = 3 Everything // dir_level The directory level (controls indent level) // node_path The path to the top level node e.g. "/History/Display" (is prepended to directory name). if (!node) { COMETError("COMET::IXmlOdb::DumpTree: node is NULL!"); return; } while (node) { // Accumulate statistics std::string node_type(node->GetNodeName()); // Treat top level 'odb' as a directory if ( node_type == "odb" ) node_type = "dir"; if ( node_type == "dir" ) fStatsNumDir +=1; else if ( node_type == "key" ) fStatsNumKey +=1; else if ( node_type == "keyarray" ) fStatsNumKeyArray +=1; else if ( node_type == "text" ) fStatsNumText +=1; else if ( node_type == "value" ) fStatsNumValue +=1; else fStatsNumOther +=1; // Extend path to this node. std::string sub_node_path(node_path); if ( sub_node_path != "/" ) sub_node_path += "/"; const char* node_name = GetAttrValue(node,"name" ); if ( node_name) sub_node_path += node_name; if ( node_type == "dir") { if ( print_level > 0 ) COMETLog(this->Indent(dir_level) << sub_node_path); } else { std::ostringstream oss; oss << node_type << " "; TList* attrs = node->GetAttributes(); TIter next(attrs); const char*text = node->GetText(); while (TXMLAttr *attr = (TXMLAttr*)next()) oss << " " << attr->GetName() << "=" << attr->GetValue(); if (text) oss << " text: \"" << node->GetText() << "\""; // Suppress empty text nodes if ( oss.str() != "text " && print_level > 1 ) COMETLog(this->Indent(dir_level) << oss.str()); } if ( node->HasChildren() && (node_type != "keyarray" || print_level > 2) ) DumpTree(node->GetChildren(),print_level,dir_level + 1,sub_node_path); node = node->GetNextNode(); } } //____________________________________________________________________________ TXMLNode* COMET::IXmlOdb::FindArrayPath(TXMLNode*node,const char* path,const char* type,Int_t index) const // Follow the ODB path through the XML DOM tree { if (!fOdb) return NULL; if (!node) node = fOdb->GetChildren(); node = FindPath(node, path); if (!node) return NULL; const char* nodename = node->GetNodeName(); const char* num_values = GetAttrValue(node,"num_values"); const char* typevalue = GetAttrValue(node,"type"); if (!typevalue || (strcasecmp(typevalue,type) != 0)) { COMETError("COMET::IXmlOdb::FindArrayPath: Type mismatch: \'" << path << "\' has type \'" << typevalue << "\', we expected \'" << type << "\'"); return NULL; } bool isKeyArray = (num_values!=NULL) && (strcmp(nodename,"keyarray")==0); if (!isKeyArray) { if (index != 0) { COMETError("COMET::IXmlOdb::FindArrayPath: Attempt to access array element " << index << ", but \'" << path << "\' is not an array"); return NULL; } return node; } Int_t max_index = atoi(num_values); if (index < 0 || index >= max_index) { COMETError("COMET::IXmlOdb::FindArrayPath: Attempt to access array element " << index << ", but size of array \' << \'" << path << "\'is " << max_index); return NULL; } TXMLNode* elem = node->GetChildren(); for (Int_t i=0; elem!=NULL; ) { const char* name = elem->GetNodeName(); if (strcmp(name,"value") == 0) { if (i == index) return elem; i++; } elem = elem->GetNextNode(); } return node; } //____________________________________________________________________________ TXMLNode* COMET::IXmlOdb::FindNode(TXMLNode*node, const char*name) const { for (; node != NULL; node = node->GetNextNode()) { if (strcmp(node->GetNodeName(),name) == 0) return node; if (node->HasChildren()) { TXMLNode* found = FindNode(node->GetChildren(),name); if (found) return found; } } return NULL; } //____________________________________________________________________________ TXMLNode* COMET::IXmlOdb::FindPath(TXMLNode*node,const char* path) const { // Follow the ODB path through the XML DOM tree if (!fOdb) return NULL; if (!node) node = fOdb->GetChildren(); while (1) { // skip leading slashes while (*path == '/') path++; if (*path == 0) return node; const Int_t kElemSize = 256; char elem[kElemSize+1]; memset(elem,0,kElemSize+1); // copy the next path element into "elem"- // copy "path" until we hit "/" or end of string for (Int_t i=0; iGetNextNode()) { const char* nodename = node->GetNodeName(); const char* namevalue = GetAttrValue(node,"name"); bool isDir = strcmp(nodename,"dir") == 0; bool isKey = strcmp(nodename,"key") == 0; bool isKeyArray = strcmp(nodename,"keyarray") == 0; if (!isKey && !isDir && !isKeyArray) continue; // // compare directory names // if (strcasecmp(elem,namevalue) == 0) { if (isDir) { // found the right subdirectory, descend into it node = node->GetChildren(); break; } else if (isKey || isKeyArray) { return node; } } } } } //____________________________________________________________________________ const char* COMET::IXmlOdb::GetAttrValue(const TXMLNode*node,const char*attrName) const { // Return the value of the named attribute // Cast away const in a good cause. TXMLNode::GetAttributes() is non-const as it // has lazy instantiation of its attributes, so first request does change its state // but only in a "const" sort of a way! TList* attrs = const_cast(node)->GetAttributes(); TIter next(attrs); while (TXMLAttr *attr = (TXMLAttr*)next()) { if (strcmp(attr->GetName(),attrName)==0) return attr->GetValue(); } return ""; } //____________________________________________________________________________ std::string COMET::IXmlOdb::Indent(Int_t level) const { // Return string of blanks to indent to the specified level. std::string blanks; for (Int_t i=0; iClearStats(); this->DumpTree(fOdb,print_level,0,""); if ( print_level > 0 ) COMETLog(""); COMETLog("Total of " << fStatsNumDir << " directories, " << fStatsNumKey << " keys, " << fStatsNumKeyArray << " keyarrays, " << fStatsNumText << " texts, " << fStatsNumValue << " values, " << fStatsNumOther << " other node types."); } //____________________________________________________________________________ Int_t COMET::IXmlOdb::odbReadAny( const char*path, Int_t index, Int_t tid,void* buf, Int_t bufsize) const { assert(!"Not implemented!"); } //____________________________________________________________________________ Int_t COMET::IXmlOdb::odbReadArraySize(const char*path) const { TXMLNode *node = FindPath(NULL,path); if (!node) return 0; const char* num_values = GetAttrValue(node,"num_values"); if (!num_values) return 1; return atoi(num_values); } //____________________________________________________________________________ Bool_t COMET::IXmlOdb::odbReadBool( const char*path, Bool_t defaultValue, Int_t index) const { TXMLNode *node = FindArrayPath(NULL,path,"BOOL",index); if (!node) return defaultValue; const char* text = node->GetText(); if (!text) return defaultValue; if (*text == 'n') return false; return true; } //____________________________________________________________________________ double COMET::IXmlOdb::odbReadDouble(const char*path, double defaultValue, Int_t index) const { TXMLNode *node = FindArrayPath(NULL,path,"DOUBLE",index); if (!node) return defaultValue; const char* text = node->GetText(); if (!text) return defaultValue; return atof(text); } //____________________________________________________________________________ Int_t COMET::IXmlOdb::odbReadInt( const char*path, Int_t defaultValue, Int_t index) const { TXMLNode *node = FindArrayPath(NULL,path,"INT",index); if (!node) return defaultValue; const char* text = node->GetText(); if (!text) return defaultValue; return atoi(text); } //____________________________________________________________________________ const char* COMET::IXmlOdb::odbReadString(const char* path, const char* defaultValue, Int_t index) const { TXMLNode *node = FindArrayPath(NULL, path, "STRING", index); if (!node) return defaultValue; const char* text = node->GetText(); if (!text) return defaultValue; return text; } //____________________________________________________________________________ UInt_t COMET::IXmlOdb::odbReadUint32(const char*name, UInt_t defaultValue, Int_t index) const { TXMLNode *node = FindArrayPath(NULL,name,"DWORD",index); if (!node) return defaultValue; const char* text = node->GetText(); if (!text) return defaultValue; return strtoul(text,NULL,0); }