/** @file XML.h @author Morgan McGuire @maintainer Morgan McGuire @created 2010-02-11 @edited 2010-02-24 Copyright 2000-2012, Morgan McGuire. All rights reserved. */ #ifndef G3D_XML_h #define G3D_XML_h #include "G3D/platform.h" #include "G3D/Table.h" #include "G3D/Array.h" #include "G3D/format.h" #include namespace G3D { class TextInput; class TextOutput; /** \brief Easy loading and saving of XML and HTML files. The XML class is intended primarily for interchange with other programs. We recommend using G3D::Any to make your own human-readable formats because it is a more general syntax, the implementation is more efficient, and contains better error handling. Every XML is either a VALUE, or a TAG that contains both a table of its XML attributes and an array of its children. Children are nested tags and the strings between the nested tags. No validation is performed, and the XML must be completely legal. XML Entity references (e.g., the ampersand codes for greater than and less than) are not automatically converted. Tags with names that begin with "!" or "?" are ignored. Comment tags must end with "-->" e.g.,
  
  
  
\sa G3D::Any, http://www.grinninglizard.com/tinyxml/ \htmlonly

  child0 ...
  ...
  child2 ...

\endhtmlonly */ class XML { public: enum Type {VALUE, TAG}; typedef Table AttributeTable; private: Type m_type; std::string m_name; std::string m_value; AttributeTable m_attribute; Array m_child; public: XML() : m_type(VALUE) {} XML(const std::string& v) : m_type(VALUE), m_value(v) {} XML(const double& v) : m_type(VALUE), m_value(format("%f", v)) {} XML(float v) : m_type(VALUE), m_value(format("%f", v)) {} XML(int v) : m_type(VALUE), m_value(format("%d", v)) {} /** \param tagType Must be XML::TAG to dismbiguate from the string constructor */ XML(Type tagType, const std::string& name, const AttributeTable& at, const Array& ch = Array()) : m_type(TAG), m_name(name), m_attribute(at), m_child(ch) { (void)tagType; debugAssert(tagType == TAG); } /** \param tagType Must be XML::TAG to dismbiguate from the string constructor */ XML(Type tagType, const std::string& name, const Array& ch = Array()) : m_type(TAG), m_name(name), m_child(ch) { (void)tagType; debugAssert(tagType == TAG); } XML(TextInput& t); void serialize(TextOutput& t) const; void deserialize(TextInput& t); void load(const std::string& filename); void save(const std::string& filename) const; void parse(const std::string &s); void unparse(std::string& s) const; const AttributeTable& attributeTable() const { return m_attribute; } const Array& childArray() const { return m_child; } /** Array size; zero for a VALUE */ int numChildren() const { return m_child.size(); } /** Attribute table size; zero for a TAG */ size_t numAttributes() const { return m_attribute.size(); } /** Return child \a i. Children are nested tags and the unquoted strings of characters between tags.*/ const XML& operator[](int i) const { return m_child[i]; } /** Return the attribute with this name. */ const XML& operator[](const std::string& k) const { return m_attribute[k]; } bool containsAttribute(const std::string& k) const { return m_attribute.containsKey(k); } /** Note that the result is always copied, making this inefficient for return values that are not VALUEs. */ XML get(const std::string& k, const XML& defaultVal) const { const XML* x = m_attribute.getPointer(k); if (x) { return *x; } else { return defaultVal; } } Type type() const { return m_type; } /** The name, if this is a TAG. */ const std::string name() const { return m_name; } /** Returns "" if a TAG. */ const std::string& string() const { return m_value; } /** Parse as a number. Returns nan() if a TAG or unparseable as a number. */ double number() const; /** Returns false if a TAG. */ bool boolean() const; operator std::string() const { return m_value; } operator bool() const { return boolean(); } operator double() const { return number(); } operator float() const { return float(number()); } operator int() const { return iRound(number()); } }; // class XML } // namespace G3D #endif