// XmlElement.cxx #include "dataset_util/XmlElement.h" #include "dataset_util/memsize.h" #include #include #include #include #include using std::string; using std::find; using std::ostream; using std::endl; //********************************************************************** // Local definitions. typedef XmlElement::ElementList ElementList; typedef XmlElement::StringList StringList; typedef XmlElement::AttMap AttMap; namespace { // Size limit for checking that a child element is not duplicated // before insertion. Checking is only done for lists with size below // this threshold. unsigned int MAX_CHILD_CHECK = 100; //********************************************************************** // Output an element. // Used by ostream. void write(ostream& lhs, const XmlElement& rhs, int level) { if ( ! rhs.is_valid() ) { lhs << "Invalid XML element"; return; } string dindent = " "; string indent = ""; for (int ilev=0; ilev 0 ) lhs << endl; // Write the name and id. lhs << indent << rhs.name(); if ( rhs.id() != "" ) { lhs << " [" << rhs.id() << "]"; } indent += dindent; // Write any attributes. int errcount = rhs.error_count(); for ( StringList::const_iterator inam=rhs.attribute_names().begin(); inam!=rhs.attribute_names().end(); ++inam ) { lhs << '\n' << indent << *inam << " = " << rhs.attribute(*inam); assert ( rhs.error_count() == errcount ) ; } // Write references. errcount = rhs.error_count(); for ( StringList::const_iterator inam=rhs.reference_names().begin(); inam!=rhs.reference_names().end(); ++inam ) { lhs << '\n' << indent << *inam << " = [" << rhs.reference(*inam) << "]"; assert ( rhs.error_count() == errcount ) ; } // Write text. if ( rhs.pcdata().size() ) { lhs << "\n" << indent << "PCDATA {" << rhs.pcdata() << "}"; } // Write children. for ( ElementList::const_iterator iele=rhs.children().begin(); iele!=rhs.children().end(); ++iele ) { const XmlElement* pchild = *iele; if ( pchild == 0 ) { lhs << '\n' << indent << "!!! NULL CHILD !!!"; } else { write(lhs, **iele, level+1); } } } } // end unnamed namespace //********************************************************************** // Member functions. //********************************************************************** // Constructor. XmlElement::XmlElement(string name) : m_err(0), m_name(name), m_id(""), m_pcdata("") { //std::cout << "XmlElement: Created " << name << " " << *this << endl; } //********************************************************************** // Copy. XmlElement::XmlElement(const XmlElement& rhs) : m_err(rhs.m_err), m_name(rhs.m_name), m_id(rhs.m_id), m_ref_names(rhs.m_ref_names), m_refs(rhs.m_refs), m_att_names(rhs.m_att_names), m_atts(rhs.m_atts), m_pcdata(rhs.m_pcdata) { for ( ElementList::const_iterator iele=rhs.children().begin(); iele!=rhs.children().end(); ++iele) { m_eles.push_back(new XmlElement(**iele)); } } //********************************************************************** // Assignment. XmlElement& XmlElement::operator=(const XmlElement& rhs) { if ( &rhs == this ) return *this; m_err = rhs.m_err; m_name = rhs.m_name; m_id = rhs.m_id; m_ref_names = rhs.m_ref_names; m_refs = rhs.m_refs; m_att_names = rhs.m_att_names; m_atts = rhs.m_atts; m_pcdata = rhs.m_pcdata; for ( ElementList::const_iterator iele=m_eles.begin(); iele!=m_eles.end(); ++iele ) { delete *iele; } m_eles.erase(m_eles.begin(), m_eles.end()); for ( ElementList::const_iterator iele=rhs.children().begin(); iele!=rhs.children().end(); ++iele) { m_eles.push_back(new XmlElement(**iele)); } return *this; } //********************************************************************** // Destructor. XmlElement::~XmlElement() { for ( ElementList::const_iterator iele=m_eles.begin(); iele!=m_eles.end(); ++iele ) { delete *iele; } } //********************************************************************** // Set the identity. int XmlElement::set_id(string id) { m_id = id; return 0; } //********************************************************************** // Add a child element. int XmlElement::add_child(const XmlElement* pele) { if ( m_eles.size() < MAX_CHILD_CHECK ) { ElementList::const_iterator iele = find(m_eles.begin(), m_eles.end(), pele); if ( iele != m_eles.end() ) { ++m_err; return 1; } } m_eles.push_back(pele); return 0; } //********************************************************************** // Add a reference to another element. int XmlElement::add_reference(string name, string ref) { AttMap::const_iterator iatt = m_refs.find(name); if ( iatt != m_refs.end() ) { ++m_err; return 1; } m_ref_names.push_back(name); m_refs[name] = ref; assert( m_ref_names.size() == m_refs.size() ); return 0; } //********************************************************************** // Add a string attribute. int XmlElement::add_attribute(string name, string att) { if ( m_atts.size() == 0 ) { m_att_names.push_back(name); m_atts.insert(std::pair(name, att)); return 0; } AttMap::const_iterator iatt = m_atts.find(name); if ( iatt != m_atts.end() ) { ++m_err; return 1; } m_att_names.push_back(name); m_atts[name] = att; assert( m_att_names.size() == m_atts.size() ); return 0; } //********************************************************************** // Add a bool attribute. int XmlElement::add_attribute_as_bool(string name, bool att) { if ( att ) { return add_attribute(name, "true"); } else { return add_attribute(name, "false"); } } //********************************************************************** // Add an int attribute. int XmlElement::add_attribute_as_int(string name, long att) { char satt[32]; sprintf(satt, "%ld", att); return add_attribute(name, satt); } //********************************************************************** // Add an unsigned int attribute. int XmlElement:: add_attribute_as_unsigned_int(string name, unsigned long att) { char satt[32]; sprintf(satt, "%lu", att); return add_attribute(name, satt); } //********************************************************************** // Set the PC data. int XmlElement::set_pcdata(string txt) { m_pcdata = txt; return 0; } //********************************************************************** // Validity. bool XmlElement::is_valid() const { return name().size() != 0; } //********************************************************************** // Find all children with a specified name. ElementList XmlElement::children(string name) const { ElementList eles; for ( ElementList::const_iterator iele=children().begin(); iele!=children().end(); ++iele ) { if ( (**iele).name() == name ) { eles.push_back(*iele); } } return eles; } //********************************************************************** // Return a single child. const XmlElement* XmlElement::single_child(string name) const { ElementList::const_iterator imatch = children().end(); for ( ElementList::const_iterator iele=children().begin(); iele!=children().end(); ++iele ) { if ( (**iele).name() == name ) { if ( imatch != children().end() ) return 0; imatch = iele; } } if ( imatch == children().end() ) return 0; return *imatch; } //********************************************************************** // Return the number of children with a specified name. ElementList::size_type XmlElement::has_children(string name) const { ElementList::size_type count = 0; for ( ElementList::const_iterator iele=children().begin(); iele!=children().end(); ++iele ) { if ( (**iele).name() == name ) { ++count; } } return count; } //********************************************************************** // Check a reference. bool XmlElement::has_reference(string name) const { AttMap::const_iterator iref = m_refs.find(name); return iref != m_refs.end(); } //********************************************************************** // Fetch a reference. string XmlElement::reference(string name) const { AttMap::const_iterator iref = m_refs.find(name); if ( iref == m_refs.end() ) { ++m_err; return ""; } return iref->second; } //********************************************************************** // Check an attribute. bool XmlElement::has_attribute(string name) const { AttMap::const_iterator iatt = m_atts.find(name); return iatt != m_atts.end(); } //********************************************************************** // Fetch an attribute. string XmlElement::attribute(string name) const { AttMap::const_iterator iatt = m_atts.find(name); if ( iatt == m_atts.end() ) { ++m_err; return ""; } return iatt->second; } //********************************************************************** // Fetch an attribute as bool. bool XmlElement::attribute_as_bool(string name) const { AttMap::const_iterator iatt = m_atts.find(name); if ( iatt == m_atts.end() ) { ++m_err; return false; } string val = iatt->second; if ( val=="true" || val=="TRUE" ) { return true; } else if ( val=="false" || val=="FALSE" ) { return false; } else { ++m_err; return false; } } //********************************************************************** // Fetch an attribute as int. long XmlElement::attribute_as_int(string name) const { AttMap::const_iterator iatt = m_atts.find(name); if ( iatt == m_atts.end() ) { ++m_err; return false; } long val = 0; int stat = sscanf(iatt->second.c_str(), "%ld", &val); if ( stat != 1 ) { ++m_err; return -999; } return val; } //********************************************************************** // Fetch an attribute as unsigned int. unsigned long XmlElement::attribute_as_unsigned_int(string name) const { AttMap::const_iterator iatt = m_atts.find(name); if ( iatt == m_atts.end() ) { ++m_err; return false; } unsigned long val = 0; int stat = sscanf(iatt->second.c_str(), "%lu", &val); if ( stat != 1 ) { ++m_err; return 9999999; } return val; } //********************************************************************** // Fetch the PC data. string XmlElement::pcdata() const { return m_pcdata; } //********************************************************************** // Write to xml text. string XmlElement::to_xml_text(string indent) const { bool nocr = indent == "NOCR"; string dindent = " "; string text = ""; if ( ! nocr ) text += indent; text += "<" + name(); string newindent = indent + dindent; if ( nocr ) newindent = "NOCR"; for ( StringList::const_iterator inam=attribute_names().begin(); inam!=attribute_names().end(); ++inam ) { string satt = attribute(*inam); for ( string::size_type ipos=0; iposto_xml_text(newindent); } } if ( ! nocr ) text += '\n' + indent; text += ""; } else { text += "/>"; } return text; } //********************************************************************** // Memory size. size_t XmlElement::memsize() const { size_t mem = 0; mem += sizeof(m_err); mem += memsize_string(m_name); mem += memsize_string(m_id); mem += sizeof(m_eles); for ( ElementList::const_iterator iele=m_eles.begin(); iele!=m_eles.end(); ++iele ) { mem += (**iele).memsize(); } mem += memsize_vector_string(m_ref_names); mem += memsize_map_string(m_refs); mem += memsize_vector_string(m_att_names); mem += memsize_map_string(m_atts); mem += memsize_string(m_pcdata); return mem; } //********************************************************************** // Free functions. //********************************************************************** // Output stream. ostream& operator<<(ostream& lhs, const XmlElement& rhs) { write(lhs, rhs, 0); return lhs; } //**********************************************************************