You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
326 lines
13 KiB
C++
326 lines
13 KiB
C++
// 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 <vector>
|
|
#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 <class T>
|
|
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 <class T>
|
|
bool AddComplexChild(const T& child, std::vector<T>* 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 <class T>
|
|
static void AcceptRepeated(std::vector<T>* elements, VisitorDriver* driver) {
|
|
typename std::vector<T>::iterator it;
|
|
for (it = elements->begin(); it != elements->end(); ++it) {
|
|
driver->Visit(*it);
|
|
}
|
|
}
|
|
|
|
// This is the internal implementation of the various DeleteTAt() methods.
|
|
template <class T>
|
|
static T DeleteFromArrayAt(std::vector<T>* 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<string> unknown_elements_array_;
|
|
// A vector of Element*'s to contain known KML elements found during parse
|
|
// to be in illegal positions, e.g. <Placemark><Document>.
|
|
std::vector<ElementPtr> 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<kmlbase::Attributes> unknown_attributes_;
|
|
// Any Element may have 0 or more xmlns attributes.
|
|
boost::scoped_ptr<kmlbase::Attributes> 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<int I>
|
|
class BasicElement : public Element {
|
|
public:
|
|
// This static method makes the class useable with ElementCast.
|
|
static KmlDomType ElementType() { return static_cast<KmlDomType>(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, <snippet> is a known element and is parsed initially into a Field,
|
|
// but since no element accepts <snippet> this results in a <snippet> 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__
|