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

// 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__