// Copyright 2008, Google Inc. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // 3. Neither the name of Google Inc. nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // This file contains the declaration of the Element and Field classes. // The Element class is the base class for the KML Object Model. All // KML complex elements are derived from this class. As the Element class // members wnd methods indicate an Element always has a given type id, and // a single parent Element. Element itself holds all unknown XML for a given // KML element including completely unknown XML, misplaced KML, // and unknown attributes. During parse a simple element is held for // a short time in the Field specialization of Element. #ifndef KML_DOM_ELEMENT_H__ #define KML_DOM_ELEMENT_H__ #include #include "boost/scoped_ptr.hpp" #include "kml/dom/kml22.h" #include "kml/dom/kml_ptr.h" #include "kml/dom/visitor_driver.h" #include "kml/base/util.h" #include "kml/base/xml_element.h" namespace kmlbase { class Attributes; } namespace kmldom { class Serializer; class Visitor; class Xsd; // This is a KML-specific implementation of the somewhat abstracted // kmlbase::XmlElement. class Element : public kmlbase::XmlElement { public: virtual ~Element(); virtual KmlDomType Type() const { return type_id_; } virtual bool IsA(KmlDomType type) const { return type == type_id_; } // This returns the element of which this is a child (if any). ElementPtr GetParent() const; // This is the concatenation of all character data found parsing this element. const string& get_char_data() const { return char_data_; } void set_char_data(const string& char_data) { char_data_ = char_data; } // TODO: AddElement() and ParseAttributes() should really be protected. // A derived class implements this to use with parsing. Element is // either a complex or simple element which the given concrete element // can accept. If the given element is a valid child the concrete element // takes ownership. The given element is attached to the concrete parent // if it is a valid complex child. If the element is a simple element // the character data is converted to the appropropriate simple type // and the passed element is discarded. If the passed element is not // a valid child of the given concrete element the AddElement method // there should pass this up to its parent for consideration. A misplaced // element will ultimately be attached to Element itself. virtual void AddElement(const ElementPtr& element); // A derived class implements this to use with parsing. A given concrete // element examines the passed attributes for any it is aware of and // passes the attributes to its parent class and ultimately to Element // itself to preserve unknown attributes. The caller takes ownership of // the passed attributes class instance and is expected to erase any items // it parses. virtual void ParseAttributes(kmlbase::Attributes* attributes); // A derived class implements this to use with serialization. See // class Serializer for more information. virtual void Serialize(Serializer& /*serialize*/ ) const {} // A derived class uses this to use with serialization. The derived // class adds its attributes to the given set and passes attributes // along to the parent and utlimately to Element itself to preserve // unknown attributes. virtual void SerializeAttributes(kmlbase::Attributes* attributes) const; // Each fully unknown element (and its children) is saved in raw XML form. void AddUnknownElement(const string& s); // Called by concrete elements to serialize unknown and/or misplaced // elements discovered at parse time. void SerializeUnknown(Serializer& serializer) const; // Returns the unknown elements. size_t get_unknown_elements_array_size() const { return unknown_elements_array_.size(); } const string& get_unknown_elements_array_at(size_t i) const { return unknown_elements_array_[i]; } // Returns the unknown legal (misplaced) elements. size_t get_misplaced_elements_array_size() const { return unknown_legal_elements_array_.size(); } const ElementPtr& get_misplaced_elements_array_at(size_t i) const { return unknown_legal_elements_array_[i]; } // Add the given set of attributes to the element's unknown attributes. // Element takes ownership of attributes. void AddUnknownAttributes(kmlbase::Attributes* attributes); // This returns a pointer to the Attributes class holding all unknown // attributes for this element found during parse. This returns NULL if // there are no unparsed attributes. Ownership of the object is retained // by the Element class. const kmlbase::Attributes* GetUnknownAttributes() const { return unknown_attributes_.get(); } // This is the set of xmlns:PREFIX=NAMESPACE attributes on the // element if any. The attribute keys are without the "xmlns:" prefix. // The default namespace is merely an "unknown" attribute // of "xmlns" in the normal "unknown" attributes list. Use // get_default_xmlns() to access the default namespace for an element. const kmlbase::Attributes* GetXmlns() const { return xmlns_.get(); } // This merges in the given set of prefix/namespace attributes into the // the xml namespaces set for this element. Each prefix is is _just_ the // namespace prefix. Each prefix added here appears in the // SerializeAttributeswith a "xmlns:" prepended. void MergeXmlns(const kmlbase::Attributes& xmlns); // Permits polymorphic use of Field methods. virtual bool SetBool(bool* /*val*/) { return false; } virtual bool SetDouble(double* /*val*/) { return false; } virtual bool SetInt(int* /*val*/) { return false; } virtual bool SetEnum(int* /*val*/) { return false; } virtual bool SetString(string* /*val*/) { return false; } // Accepts the visitor for this element (this must be overridden for each // element type). // TODO(dbeaumont): Make pure virtual when all sub-classes implement Accept(). virtual void Accept(Visitor* visitor); // This needs to be implemented by subclasses with child elements and must // call its parent's implementation first. The default implementation does // nothing. virtual void AcceptChildren(VisitorDriver* /*driver*/) { /* Inlinable for efficiency */ } protected: // Element is an abstract base class and is never created directly. Element(); Element(KmlDomType type_id); // This sets the given complex child to a field of this element. // The intended usage is to implement the set_child() and clear_child() // methods in a concrete element. template bool SetComplexChild(const T& child, T* field) { if (child == NULL) { // TODO: remove child and children from ID maps... *field = NULL; // Assign removes reference and possibly deletes Element. return true; } else if (child->SetParent(this)) { *field = child; // This first releases the reference to previous field. return true; } return false; } // This adds the given complex child to an array in this element. template bool AddComplexChild(const T& child, std::vector* vec) { // NULL child ignored. if (child && child->SetParent(this)) { vec->push_back(child); return true; } return false; } // Allows subclasses to easily visit repeated fields. template static void AcceptRepeated(std::vector* elements, VisitorDriver* driver) { typename std::vector::iterator it; for (it = elements->begin(); it != elements->end(); ++it) { driver->Visit(*it); } } // This is the internal implementation of the various DeleteTAt() methods. template static T DeleteFromArrayAt(std::vector* array, size_t i) { if (!array || i >= array->size()) { return NULL; } T e = (*array)[i]; array->erase(array->begin() + i); // TODO: notify e's XmlFile about the delete (kmlengine::KmlFile, for // example would want to remove e from its internal maps). // TODO: disparent e return e; } private: KmlDomType type_id_; string char_data_; // A vector of strings to contain unknown non-KML elements discovered during // parse. std::vector unknown_elements_array_; // A vector of Element*'s to contain known KML elements found during parse // to be in illegal positions, e.g. . std::vector unknown_legal_elements_array_; // Unknown attributes found during parse are copied out and a pointer is // stored. The object is dynamically allocated so every element is not // burdened with an unnecessary Attributes object. boost::scoped_ptr unknown_attributes_; // Any Element may have 0 or more xmlns attributes. boost::scoped_ptr xmlns_; LIBKML_DISALLOW_EVIL_CONSTRUCTORS(Element); }; // This class implements common code for use in serializing most elements. // Intended usage is as follows: // ConcreteElement::Serialize(Serializer& serializer) const { // ElementSerializer element_serializer(Type(), serializer); // // serialize each child element and/or field // // ElementSerializer dtor ends serialization properly. // } class ElementSerializer { public: ElementSerializer(const Element& element, Serializer& serializer); ~ElementSerializer(); private: const Element& element_; Serializer& serializer_; }; // This class template is essentially common code for all elements based // directly on Element. template class BasicElement : public Element { public: // This static method makes the class useable with ElementCast. static KmlDomType ElementType() { return static_cast(I); } virtual KmlDomType Type() const { return ElementType(); } virtual bool IsA(KmlDomType type) const { return type == ElementType(); } }; // A field is generally short lived and holds the element id and character data // for that field during parse. When a Field is presented to AddElement() and // is recognized by a parent element that parent typically copies the value of // the Field to a field held within the parent. However, when a "misplaced" // field is parsed it is held in this form in Element's misplaced elements // list. Known child fields are serialized by their parents, but a Serialize // method implementation is provided specifically to provide a means to // serialize a Field held in an Element's misplaced elements list. For // example, is a known element and is parsed initially into a Field, // but since no element accepts this results in a Field in // the parent element's misplaced elements list. class Field : public Element { public: Field(KmlDomType type_id); // Serialize this Field to the given serializer. See the class comment above // for when this is used. virtual void Serialize(Serializer& serialize) const; // Sets the given bool from the character data. If no val pointer is // supplied false is returned, else true is returned and the val is set. bool SetBool(bool* val); // Sets the given double from the character data. If no val pointer is // supplied false is returned, else true is returned and the val is set. bool SetDouble(double *val); // Sets the given int from the character data. If no val pointer is // supplied false is returned, else true is returned and the val is set. bool SetInt(int* val); // Sets the given enum from the character data. If no val pointer is // supplied false is returned, else true is returned and the val is set. bool SetEnum(int* enum_val); // Sets the given string from the character data. If no val pointer is // supplied false is returned, else true is returned and the val is set. bool SetString(string* val); private: const Xsd& xsd_; LIBKML_DISALLOW_EVIL_CONSTRUCTORS(Field); }; } // namespace kmldom #endif // KML_DOM_ELEMENT_H__