Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

DictNode.cxx

Go to the documentation of this file.
00001 // $Header: /nfs/slac/g/glast/ground/cvs/xmlUtil/src/id/DictNode.cxx,v 1.10 2002/04/05 18:26:44 jrb Exp $
00002 #include <dom/DOM_Element.hpp>
00003 #include <dom/DOMString.hpp>
00004 #include "xml/Dom.h"
00005 #include "xmlUtil/id/DictNode.h"
00006 #include "xmlUtil/id/DictFieldMan.h"
00007 #include <assert.h>
00008 
00009 namespace xmlUtil {
00010   std::ostream* DictNode::m_err = &(std::cout);
00011   DictNode::DictNode(DOM_Element elt, DictNode *parent,
00012                      DictFieldMan *fieldMan) : 
00013     m_children(0), m_parent(parent), m_parConstraints(0), 
00014     m_myConstraints(0)   {
00015     // check element type is OK.  Shouldn't be a problem if
00016     // the xml file validates.  Note sense of assert is:
00017     //   abort program if assertion is *false*
00018     assert( (elt.getTagName().equals("dictNode")) ||
00019             (elt.getTagName().equals("dictRoot"))     ) ;
00020 
00021     // Field name stuff:
00022     std::string fName = 
00023       std::string(xml::Dom::transToChar(elt.getAttribute("fieldName")));
00024     
00025     m_field = fieldMan->find(fName.c_str());
00026     assert(m_field != 0);
00027     // Do something if it doesn't exist?? Shouldn't be terribly
00028     // necessary by ID/IDREF mechanism
00029 
00030     DOM_Element child = xml::Dom::getFirstChildElement(elt);
00031     // Could be a leaf with no children
00032     if (child == DOM_Element()) return;
00033 
00034     if ((child.getTagName()).equals("pValues")) { // parent constraints
00035       DOM_Element gChild = xml::Dom::getFirstChildElement(child);
00036       m_parConstraints = new DictConstraints(gChild);
00037       
00038       // check for compatibility
00039       DictConstraints* fromParent = 0;
00040       if (parent->m_myConstraints) fromParent = (parent->m_myConstraints);
00041       else {
00042         fromParent = parent->m_field->getConstraints();
00043       }
00044       if (fromParent) {
00045         bool allowed = (fromParent->allowed(m_parConstraints));
00046         if (!allowed) {
00047           assert(allowed);
00048         }
00049       }
00050       child = xml::Dom::getSiblingElement(child);
00051       if (child == DOM_Element()) return;    // new Dec. 4
00052     }
00053     
00054     // Next up we might have our own constraint
00055     if (!(child.getTagName().equals("dictNode")) ) {
00056       m_myConstraints = new DictConstraints(child);
00057       
00058       // Check it's consistent with constraints on our own field,
00059       // if any
00060       DictConstraints* fCon = m_field->getConstraints();
00061       if (fCon != 0) {
00062         assert(fCon->allowed(m_myConstraints));
00063       }
00064       child = xml::Dom::getSiblingElement(child);
00065     }
00066     
00067     // All that's left are child nodes, if any
00068     
00069     while (child != DOM_Element()) {
00070       DictNode *nextChild = new DictNode(child, this, fieldMan);
00071       
00072       m_children.push_back(nextChild);
00073       child = xml::Dom::getSiblingElement(child);
00074     }
00075     // Finally, how about checking for consistency among children?
00076     if (!consistentChildren()) {
00077       std::cout << "Inconsistent children, fieldname " <<
00078         m_field->getName();
00079       // make a fuss
00080     }
00081   }
00082   
00083   // If 0 or 1 child, we're done.  Else 
00084   // *no* children have parent constraints
00085   //        or
00086   // *all* children must have parent constraints, 
00087   // and they must define sets
00088   // such that for any pair, the sets are disjoint or
00089   // they are identical.  Now collect all nodes with identical
00090   // parent constraints and check their "personal" value constraints.
00091   // They must be disjoint.
00092   bool DictNode::consistentChildren() {
00093     if (m_children.size() < 2) return true; // most common case
00094     
00095     // Either all children must have parent-value constraints or
00096     // none can.
00097     ConstNodeIterator it = m_children.begin();
00098     bool childMode = ((*it)->m_parConstraints != 0);
00099     ++it;
00100     for (; it < m_children.end(); ++it) {
00101       if (((*it)->m_parConstraints != 0) != childMode) {
00102         (*m_err) << "Mixed parent-constraint mode among children " 
00103                  << std::endl;
00104         (*m_err) << "Current node has field name " << this->m_field->getName()
00105                  << std::endl;
00106         return false;
00107       }
00108     }
00109     if (!childMode) { // no parent constraints
00110       return valuesDisjoint(m_children.begin(), m_children.end());
00111     }
00112     
00113     // Otherwise sort nodes by minValue of parent constraint
00114     POrder parOrder;
00115     std::sort(m_children.begin(), m_children.end(), parOrder);
00116     
00117     // Check that parent constraints are disjoint or identical
00118     for (it = m_children.begin(); (it + 1) != m_children.end(); ++it) {
00119       DictConstraints *par1 = (*it)->m_parConstraints;
00120       DictConstraints *par2 = (*(it + 1))->m_parConstraints;
00121       
00122       if (  (!par1->equals(*par2)) &&
00123             (!par1->disjoint(*par2))  ) {
00124         (*m_err) << "Non-disjoint parent constraints among children" 
00125                  << std::endl;
00126         (*m_err) << "Current node has field name " << this->m_field->getName()
00127                  << std::endl;
00128         return false;
00129       }
00130     }
00131     
00132     // Finally need to check that child values are disjoint
00133     // within subcollection of nodes with same parent constraints
00134     it = m_children.begin();
00135     while (it  != m_children.end() ) {
00136       ConstNodeIterator follow = it + 1;
00137       unsigned   ourMin = (*it)->m_parConstraints->getMin();
00138       
00139       // If we're ever starting a new collection to check at the
00140       // last child, we're done
00141       if (follow == m_children.end()) return true;
00142       while (follow != m_children.end()) {
00143         DictConstraints *par2 = (*follow)->m_parConstraints;
00144         
00145         if (par2->getMin() != ourMin) {
00146           --follow;
00147           break;
00148         }
00149         ++follow;
00150         
00151       }
00152       // If we got here, it's time to check out a collection of children
00153       bool ok = valuesDisjoint(it, follow);
00154       if (!ok) {
00155         (*m_err) << 
00156           "Non-disjoint values for children with same parent constraints" 
00157                  << std::endl;
00158         (*m_err) << "Current node has field name " << this->m_field->getName()
00159                  << std::endl;
00160         return false;
00161       }
00162       
00163       // Otherwise see if there is another bunch left
00164       it = ++follow;
00165     }
00166     return true;
00167   }
00168 
00169   bool DictNode::consistentParent() {
00170     if (!m_parConstraints) return true;
00171 
00172     if (DictConstraints *parConstraints = m_parent->m_myConstraints) {
00173       bool ok = parConstraints->allowed(*m_parConstraints);
00174       if (!ok) { 
00175         (*m_err) << 
00176           "Parent value constraints and local parent constraints inconsistent"
00177                  << std::endl;
00178         (*m_err) << "Current node has field name " << this->m_field->getName()
00179                  << std::endl;
00180         
00181         return ok;
00182       }
00183     }
00184     else if (DictConstraints *parConstraints = 
00185              m_parent->m_field->getConstraints()) {
00186       bool ok = parConstraints->allowed(*m_parConstraints);
00187       if (!ok) { 
00188         (*m_err) << 
00189           "Global value constraints on parent, local parent constraints clash"
00190                  << std::endl;
00191         (*m_err) << "Current node has field name " << this->m_field->getName()
00192                  << std::endl;
00193       }
00194       return ok;
00195     }
00196     return true;
00197   }
00198 
00199   bool DictNode::consistentValues() {
00200     if (!m_myConstraints) return true;
00201 
00202     DictConstraints *fieldConstraints = m_field->getConstraints();
00203     
00204     if (!fieldConstraints) return true;
00205     
00206     bool ok= fieldConstraints->allowed(*m_myConstraints);
00207     if (!ok) {
00208       (*m_err) << "local value constraints and global field constraints clash"
00209                << std::endl;
00210       (*m_err) << "Current node has field name " << this->m_field->getName()
00211                  << std::endl;
00212     }
00213     return ok;
00214   }
00215   
00216   bool DictNode::valuesDisjoint(ConstNodeIterator start, 
00217                                 ConstNodeIterator last) {
00218     if (*start == *last) return true;
00219     
00220     ConstNodeIterator pCurrentNode = start;
00221     std::set<unsigned> values;
00222 
00223     if (!(*start)->m_myConstraints) { // There had better be some
00224       //associated with the field name;  copy them
00225       DictConstraints* fieldCon = (*start)->m_myConstraints = 
00226         new DictConstraints(*((*start)->m_field->getConstraints()));
00227       assert(fieldCon != 0);
00228     }
00229 
00230     (*start)->m_myConstraints->insertValues(values);
00231 
00232     while (pCurrentNode != last) {
00233 
00234       ++pCurrentNode;
00235       
00236       // Make a new set containing values for current node
00237       std::set<unsigned> curValues;
00238 
00239       if (!(*pCurrentNode)->m_myConstraints) { // There had better be some
00240       //associated with the field name;  copy them
00241         DictConstraints*  fieldCon = (*pCurrentNode)->m_myConstraints = 
00242         new DictConstraints(*((*pCurrentNode)->m_field->getConstraints()));
00243         assert(fieldCon != 0);
00244       }
00245 
00246       (*pCurrentNode)->m_myConstraints->insertValues(curValues);
00247 
00248       // See if it intersects accumulated values from previous nodes
00249       std::vector<unsigned> intersect;
00250       std::set_intersection(values.begin(), values.end(), curValues.begin(),
00251                             curValues.end(), intersect.begin());
00252       if (intersect.size() > 0) return false;
00253       
00254       // If not, continue to accumulate
00255       (*pCurrentNode)->m_myConstraints->insertValues(values);
00256 
00257     } 
00258     return true;
00259     
00260   }
00261   
00262   bool DictNode::allowed(const unsigned value) const {
00263     if (!m_myConstraints) {
00264       return m_field->allowed(value);
00265     }
00266     else {
00267       return m_myConstraints->allowed(value);
00268     }
00269   }
00270 
00271   bool  DictNode::allowedChild(std::string childField, unsigned childValue, 
00272                                unsigned myValue) const {
00273     if (!allowed(myValue)) return false;
00274 
00275     for (ConstNodeIterator it = m_children.begin(); it != m_children.end();
00276          ++it) {
00277       if (  ((*it)->getField()).getName() == childField) {
00278         return allowedChild(*it, childValue, myValue);
00279       }
00280     }
00281     // Never found child with correct field name
00282     return false;
00283   }
00284           
00285   bool  DictNode::allowedChild(unsigned childValue, 
00286                                unsigned myValue) const {
00287 
00288     if (!allowed(myValue)) return false;
00289     for (ConstNodeIterator it = m_children.begin(); it != m_children.end();
00290          ++it) {
00291       if  (allowedChild(*it, childValue, myValue)) return true;
00292     }
00293     return false;
00294   }
00295 
00296   bool DictNode::allowedChild(const DictNode* const child, unsigned childValue,
00297                               unsigned myValue) const {
00298     if (child->m_parConstraints) {
00299       if (!(child->m_parConstraints)->allowed(myValue)) return false;
00300     }
00301     return child->allowed(childValue);
00302   }
00303 
00304   bool DictNode::allowIdentifier(Identifier::const_iterator idIt, 
00305                                  Identifier::const_iterator end,
00306                                  NamedId *named) {
00307     if (!allowed(*idIt)) return false;
00308     if (named != 0) named->addField(m_field->getName(), *idIt);
00309     Identifier::const_iterator tmp = idIt;
00310     ++tmp;
00311     if (tmp == end) return true;
00312 
00313     //look for children allowing our value for parent node
00314     for (ConstNodeIterator it = m_children.begin(); it != m_children.end();
00315          it++) {
00316       DictNode *child = *it;
00317       if ( (child->m_parConstraints == 0) ||
00318            (child->m_parConstraints->allowed(*idIt)) ) {
00319         if (child->allowIdentifier(++idIt, end, named)) return true;
00320       }
00321     }
00322     // Didn't work out so remove ourselves
00323     if (named != 0) named->popField();
00324     return false;
00325   }
00326 
00327   bool DictNode::allowIdentifier(const Identifier& id, NamedId* named) {
00328     Identifier::const_iterator idIt = id.begin();
00329     return allowIdentifier(idIt, id.end(), named);
00330   }
00331     
00332   bool DictNode::allowNamedId(const NamedId& nId) {
00333     NamedId::FieldIt nIdIt = nId.m_fields->begin();
00334     return allowNamedId(nIdIt, nId.m_fields->end());
00335   }
00336 
00337   bool DictNode::allowNamedId(NamedId::FieldIt nIdIt,
00338                               NamedId::FieldIt end) {
00339     // Check information for first field matches
00340 
00341     // These aren't supposed to happen
00342     if (nIdIt == end) return true;
00343     if (!(*nIdIt)) return false; 
00344 
00345     if ( ((*nIdIt)->name).compare(m_field->getName()) ) return false;
00346     if (!allowed((*nIdIt)->value) ) return false;
00347 
00348     NamedId::FieldIt tmp = nIdIt;
00349     ++tmp;
00350     if (tmp == end) return true; //done
00351 
00352     // Now search children for match of remaining fields
00353     for (ConstNodeIterator it = m_children.begin(); it != m_children.end();
00354          it++) {
00355       DictNode *child = *it;
00356       if ( (child->m_parConstraints == 0) ||
00357            (child->m_parConstraints->allowed((*nIdIt)->value) ) ) {
00358         if (child->allowNamedId(++nIdIt, end) ) return true;
00359       }
00360     }
00361     return false;
00362   }
00363 
00364   bool DictNode::allowNameSeq(const NameSeq& seq) const {
00365     NameSeq::const_iterator seqIt = seq.begin();
00366     return allowNameSeq(seqIt, seq.end());
00367   }
00368 
00369   bool DictNode::allowNameSeq(NameSeq::const_iterator seqIt,
00370                               NameSeq::const_iterator end) const {
00371     if (seqIt == end) return true;
00372     if ( (*seqIt)->compare(m_field->getName())  ) return false;
00373 
00374     NameSeq::const_iterator tmp = seqIt;
00375     ++tmp;
00376     if (tmp == end) return true; // done
00377     
00378     // Now search children for match of remaining fields
00379     for (ConstNodeIterator it = m_children.begin(); it != m_children.end();
00380          it++) {
00381       DictNode *child = *it;
00382       if (child->allowNameSeq(++seqIt, end) ) return true;
00383     }
00384     return false;
00385 
00386     /* TO DO */
00387   }
00388 
00389 
00390   bool  DictNode::addChild(DictNode* child) {
00391     if ((m_myConstraints != 0) & (child->m_parConstraints != 0)) {
00392       if (!(m_myConstraints->allowed(child->m_parConstraints))) return false;
00393     }
00394     m_children.push_back(child);
00395     return true;
00396   }
00397 
00398 
00399   // Support visitors.
00400   // Should there be a non-recursive version?
00401   // Should there be an option to visit associated field, constraints?
00402   bool DictNode::accept(DictVisitor* vis) {
00403     // Call back visitor for child nodes, then self
00404 
00405     for (ConstNodeIterator it = m_children.begin(); it != m_children.end();
00406          it++) {
00407       bool keepGoing = (*it)->accept(vis);
00408       if (!keepGoing) return false;
00409     } 
00410 
00411     return  vis->visitNode(this);
00412   }
00413 
00414   DictNode::DictNode(const DictNode& toCopy) : DictObject(toCopy) {
00415     deepCopy(toCopy);
00416   }
00417 
00418   DictNode& DictNode::operator=(const DictNode& d) {
00419     throw No_Assignment();
00420   }
00421 
00422   void DictNode::deepCopy(const DictNode& d) {
00423     // Don't copy parent.  Nodes created with copy constructor
00424     // are parentless.  Use addChild after creation.
00425     // Also have to get parent constraints some other way
00426     m_parent = 0;
00427     m_parConstraints = 0;
00428     if (d.m_field) {
00429       m_field = new DictField(*(d.m_field));
00430     }
00431     else m_field = 0;
00432 
00433     if (d.m_myConstraints) {
00434       m_myConstraints = new DictConstraints(*(d.m_myConstraints));
00435     }
00436     else m_myConstraints = 0;
00437 
00438     // Now for child nodes
00439     for (ConstNodeIterator it = d.m_children.begin(); 
00440          it != d.m_children.end(); ++it) {
00441       DictNode *newChild = new DictNode(**it);
00442       DictConstraints *oldParConstraints = (*it)->m_parConstraints;
00443 
00444       newChild->m_parConstraints = (oldParConstraints) ? 
00445         new DictConstraints(*oldParConstraints) : 0;
00446       // Need some exception handling here.  addChild returns 
00447       // true or false, depending on whether child actually was
00448       // added or not.
00449       addChild(newChild);
00450     }
00451   }
00452 
00453   DictNode::~DictNode() {
00454     if (m_parConstraints != 0) {
00455       delete m_parConstraints;
00456       m_parConstraints = 0;
00457     }
00458     if (m_myConstraints != 0) {
00459       delete m_myConstraints;
00460       m_myConstraints = 0;
00461     }
00462     for (NodeIterator it = m_children.begin(); 
00463          it != m_children.end(); ++it) {
00464       delete *it;
00465     }
00466   }
00467 }                  // end namespace
00468 
00469 

Generated on Wed Oct 16 14:02:47 2002 by doxygen1.2.13.1 written by Dimitri van Heesch, © 1997-2001