make otml simpler and easier to use, improve error handling/exceptions

This commit is contained in:
Eduardo Bart
2011-08-19 15:53:23 -03:00
parent f9e7d52ac0
commit 033f14780d
32 changed files with 646 additions and 622 deletions

View File

@@ -3,6 +3,5 @@
#include "otmldocument.h"
#include "otmlnode.h"
#include "otmlnodeext.h"
#endif
#endif

View File

@@ -15,7 +15,7 @@ OTMLDocumentPtr OTMLDocument::parse(const std::string& fileName)
{
std::stringstream fin;
g_resources.loadFile(fileName, fin);
return parse(fin, fileName);
return parse(fin, g_resources.resolvePath(fileName));
}
OTMLDocumentPtr OTMLDocument::parse(std::istream& in, const std::string& source)
@@ -34,8 +34,7 @@ std::string OTMLDocument::emit()
bool OTMLDocument::save(const std::string& fileName)
{
setSource(fileName);
m_source = fileName;
return g_resources.saveFile(fileName, emit());
}

View File

@@ -16,13 +16,15 @@ std::string OTMLEmitter::emitNode(const OTMLNodePtr& node, int currentDepth)
ss << node->tag();
// add ':' to if the node is unique or has value
if(node->hasValue() || node->isUnique())
if(node->hasValue() || node->isUnique() || node->isNull())
ss << ":";
} else
ss << "-";
// emit node value
if(node->hasValue()) {
if(node->isNull())
ss << " ~";
else if(node->hasValue()) {
ss << " ";
std::string value = node->value();
@@ -61,7 +63,7 @@ std::string OTMLEmitter::emitNode(const OTMLNodePtr& node, int currentDepth)
for(int i=0;i<node->size();++i) {
if(currentDepth >= 0 || i != 0)
ss << "\n";
ss << emitNode(node->at(i), currentDepth+1);
ss << emitNode(node->atIndex(i), currentDepth+1);
}
return ss.str();

View File

@@ -14,9 +14,6 @@ public:
virtual const char* what() const throw() { return m_what.c_str(); }
protected:
OTMLException() { }
void generateErrorMessage(const OTMLDocumentPtr& doc, const std::string& error, int line);
void generateErrorMessage(const OTMLNodePtr& node, const std::string& error);
std::string m_what;
};

View File

@@ -2,157 +2,86 @@
#include "otmlemitter.h"
#include "otmldocument.h"
OTMLNode::OTMLNode()
OTMLNodePtr OTMLNode::create(std::string tag, bool unique)
{
m_unique = false;
OTMLNodePtr node(new OTMLNode);
node->setTag(tag);
node->setUnique(unique);
return node;
}
std::string OTMLNode::tag() const
OTMLNodePtr OTMLNode::create(std::string tag, std::string value)
{
return m_tag;
OTMLNodePtr node(new OTMLNode);
node->setTag(tag);
node->setValue(value);
node->setUnique(true);
return node;
}
std::string OTMLNode::value() const
bool OTMLNode::hasChildren() const
{
// ~ is an alias for no value
if(m_value == "~")
return fw::empty_string;
return m_value;
}
int OTMLNode::size() const
{
return m_childNodes.size();
}
OTMLNodePtr OTMLNode::parent() const
{
return m_parent.lock();
}
const OTMLNodeList& OTMLNode::childNodes() const
{
return m_childNodes;
}
std::string OTMLNode::source() const
{
return m_source;
}
bool OTMLNode::hasTag() const
{
return !m_tag.empty();
}
bool OTMLNode::hasValue() const
{
return (!m_value.empty() && m_value != "~");
}
bool OTMLNode::hasChildNodes() const
{
return size() > 0;
}
bool OTMLNode::hasChild(const std::string& childTag) const
{
return !!get(childTag);
}
bool OTMLNode::hasChild(int index) const
{
return !!get(index);
}
bool OTMLNode::isUnique() const
{
return m_unique;
}
void OTMLNode::setTag(std::string tag)
{
m_tag = tag;
// valued nodes that has tags are always unique
if(!m_value.empty() && hasTag())
setUnique();
}
void OTMLNode::setValue(const std::string& value)
{
m_value = value;
// valued nodes that has tags are always unique
if(!m_value.empty() && hasTag())
setUnique();
}
void OTMLNode::setParent(const OTMLNodePtr& parent)
{
m_parent = parent;
}
void OTMLNode::setUnique(bool unique)
{
m_unique = unique;
}
void OTMLNode::setSource(const std::string& source)
{
m_source = source;
}
OTMLNodePtr OTMLNode::at(const std::string& childTag)
{
for(const OTMLNodePtr& child : m_childNodes) {
if(child->tag() == childTag)
return child;
int count = 0;
for(const OTMLNodePtr& child : m_children) {
if(!child->isNull())
count++;
}
throw OTMLException(shared_from_this(), fw::mkstr("child node with tag '", childTag, "' not found"));
return nullptr;
}
OTMLNodePtr OTMLNode::at(int childIndex)
{
if(childIndex < size() && childIndex >= 0)
return m_childNodes[childIndex];
throw OTMLException(shared_from_this(), fw::mkstr("child node at index '", childIndex, "' not found"));
return nullptr;
return count > 0;
}
OTMLNodePtr OTMLNode::get(const std::string& childTag) const
{
for(const OTMLNodePtr& child : m_childNodes) {
if(child->tag() == childTag)
for(const OTMLNodePtr& child : m_children) {
if(child->tag() == childTag && !child->isNull())
return child;
}
return nullptr;
}
OTMLNodePtr OTMLNode::get(int childIndex) const
OTMLNodePtr OTMLNode::getIndex(int childIndex) const
{
if(childIndex < size() && childIndex >= 0)
return m_childNodes[childIndex];
return m_children[childIndex];
return nullptr;
}
OTMLNodePtr OTMLNode::at(const std::string& childTag)
{
OTMLNodePtr res;
for(const OTMLNodePtr& child : m_children) {
if(child->tag() == childTag && !child->isNull()) {
res = child;
break;
}
}
if(!res)
throw OTMLException(shared_from_this(), fw::mkstr("child node with tag '", childTag, "' not found"));
return res;
}
OTMLNodePtr OTMLNode::atIndex(int childIndex)
{
if(childIndex >= size() || childIndex < 0)
throw OTMLException(shared_from_this(), fw::mkstr("child node with index '", childIndex, "' not found"));
return m_children[childIndex];
}
void OTMLNode::addChild(const OTMLNodePtr& newChild)
{
// replace is needed when the tag is marked as unique
if(newChild->hasTag()) {
for(OTMLNodePtr node : m_childNodes) {
for(const OTMLNodePtr& node : m_children) {
if(node->tag() == newChild->tag() && (node->isUnique() || newChild->isUnique())) {
newChild->setUnique();
newChild->setUnique(true);
replaceChild(node, newChild);
// remove any other child with the same tag
auto it = m_childNodes.begin();
while(it != m_childNodes.end()) {
auto it = m_children.begin();
while(it != m_children.end()) {
OTMLNodePtr node = (*it);
if(node != newChild && node->tag() == newChild->tag()) {
node->setParent(nullptr);
it = m_childNodes.erase(it);
it = m_children.erase(it);
} else
++it;
}
@@ -161,60 +90,67 @@ void OTMLNode::addChild(const OTMLNodePtr& newChild)
}
}
m_childNodes.push_back(newChild);
m_children.push_back(newChild);
newChild->setParent(shared_from_this());
}
bool OTMLNode::removeChild(const OTMLNodePtr& oldChild)
{
for(auto it = m_childNodes.begin(); it != m_childNodes.end(); ++it) {
if((*it) == oldChild) {
m_childNodes.erase(it);
oldChild->setParent(nullptr);
return true;
}
auto it = std::find(m_children.begin(), m_children.end(), oldChild);
if(it != m_children.end()) {
m_children.erase(it);
oldChild->setParent(nullptr);
return true;
}
return false;
}
bool OTMLNode::replaceChild(const OTMLNodePtr& oldChild, const OTMLNodePtr& newChild)
{
for(auto it = m_childNodes.begin(); it != m_childNodes.end(); ++it) {
if((*it) == oldChild) {
oldChild->setParent(nullptr);
newChild->setParent(shared_from_this());
it = m_childNodes.erase(it);
m_childNodes.insert(it, newChild);
return true;
}
auto it = std::find(m_children.begin(), m_children.end(), oldChild);
if(it != m_children.end()) {
oldChild->setParent(nullptr);
newChild->setParent(shared_from_this());
it = m_children.erase(it);
m_children.insert(it, newChild);
return true;
}
return false;
}
void OTMLNode::clear()
{
m_childNodes.clear();
}
void OTMLNode::merge(const OTMLNodePtr& node)
{
for(const OTMLNodePtr& child : node->childNodes()) {
OTMLNodePtr newNode(new OTMLNode);
newNode->setUnique(child->isUnique());
newNode->setTag(child->tag());
newNode->setValue(child->value());
addChild(newNode);
newNode->merge(child);
}
for(const OTMLNodePtr& child : node->m_children)
addChild(child->clone());
setTag(node->tag());
setSource(node->source());
}
void OTMLNode::clear()
{
for(const OTMLNodePtr& child : m_children)
child->setParent(nullptr);
m_children.clear();
}
OTMLNodeList OTMLNode::children() const
{
OTMLNodeList children;
for(const OTMLNodePtr& child : m_children)
if(!child->isNull())
children.push_back(child);
return children;
}
OTMLNodePtr OTMLNode::clone() const
{
OTMLNodePtr myClone(new OTMLNode);
myClone->setTag(tag());
myClone->setValue(value());
myClone->setUnique(isUnique());
for(OTMLNodePtr child : childNodes())
myClone->setTag(m_tag);
myClone->setValue(m_value);
myClone->setUnique(m_unique);
myClone->setNull(m_null);
myClone->setSource(m_source);
for(const OTMLNodePtr& child : m_children)
myClone->addChild(child->clone());
return myClone;
}
@@ -223,3 +159,4 @@ std::string OTMLNode::emit()
{
return OTMLEmitter::emitNode(shared_from_this(), 0);
}

View File

@@ -2,214 +2,138 @@
#define OTMLNODE_H
#include "declarations.h"
#include "otmlexception.h"
class OTMLNode : public std::enable_shared_from_this<OTMLNode>
{
public:
OTMLNode();
virtual ~OTMLNode() { }
std::string value() const;
std::string tag() const;
int size() const;
OTMLNodePtr parent() const;
const OTMLNodeList& childNodes() const;
std::string source() const;
static OTMLNodePtr create(std::string tag = fw::empty_string, bool unique = false);
static OTMLNodePtr create(std::string tag, std::string value);
bool hasTag() const;
bool hasValue() const;
bool hasChildNodes() const;
bool hasChild(const std::string& childTag) const;
bool hasChild(int index) const;
bool isUnique() const;
std::string tag() const { return m_tag; }
int size() const { return m_children.size(); }
OTMLNodePtr parent() const { return m_parent.lock(); }
std::string source() const { return m_source; }
void setTag(std::string tag);
void setValue(const std::string& value);
void setParent(const OTMLNodePtr& parent);
void setUnique(bool unique = true);
void setSource(const std::string& source);
bool isUnique() const { return m_unique; }
bool isNull() const { return m_null; }
/// Same as get but if the child node doesn't exist throws an OTMLException
OTMLNodePtr at(const std::string& childTag);
OTMLNodePtr at(int childIndex);
bool hasTag() const { return !m_tag.empty(); }
bool hasValue() const { return !m_value.empty(); }
bool hasChildren() const;
bool hasChildAt(const std::string& childTag) { return !!get(childTag); }
bool hasChildAtIndex(int childIndex) { return !!getIndex(childIndex); }
void setTag(std::string tag) { m_tag = tag; }
void setValue(const std::string& value) { m_value = value; }
void setNull(bool null) { m_null = null; }
void setUnique(bool unique) { m_unique = unique; }
void setParent(const OTMLNodePtr& parent) { m_parent = parent; }
void setSource(const std::string& source) { m_source = source; }
/// Get a child node, if doesn't exists returns nullptr
OTMLNodePtr get(const std::string& childTag) const;
OTMLNodePtr get(int childIndex) const;
OTMLNodePtr getIndex(int childIndex) const;
OTMLNodePtr at(const std::string& childTag);
OTMLNodePtr atIndex(int childIndex);
void addChild(const OTMLNodePtr& newChild);
bool removeChild(const OTMLNodePtr& oldChild);
bool replaceChild(const OTMLNodePtr& oldChild, const OTMLNodePtr& newChild);
/// Remove all children
void merge(const OTMLNodePtr& node);
void clear();
/// Recursively copy children from another node to this node
void merge(const OTMLNodePtr& node);
/// Recursively clone this node into a new one
OTMLNodeList children() const;
OTMLNodePtr clone() const;
/// Emits this node to a std::string
virtual std::string emit();
template<typename T>
T read();
template<typename T>
T read(const T& def);
template<typename T, typename U>
T readAt(const U& childIdentifier);
template<typename T, typename U>
T readAt(const U& childIdentifier, const T& def);
template<typename T = std::string>
T value();
template<typename T = std::string>
T valueAt(const std::string& childTag);
template<typename T = std::string>
T valueAtIndex(int childIndex);
template<typename T = std::string>
T valueAt(const std::string& childTag, const T& def);
template<typename T = std::string>
T valueAtIndex(int childIndex, const T& def);
template<typename T>
void write(const T& v);
template<typename T>
void writeAt(const std::string& childTag, const T& v);
template<typename T>
void writeIn(const T& v);
private:
virtual std::string emit();
protected:
OTMLNode() : m_unique(false), m_null(false) { }
OTMLNodeList m_children;
OTMLNodeWeakPtr m_parent;
std::string m_tag;
std::string m_value;
std::string m_source;
bool m_unique;
OTMLNodeList m_childNodes;
OTMLNodeWeakPtr m_parent;
bool m_null;
};
// templates for reading values
#include "otmlexception.h"
template<typename T>
T OTMLNode::read() {
T v;
if(!from_otmlnode(shared_from_this(), v))
throw OTMLException(shared_from_this(),
fw::mkstr("failed to cast node value to type '", fw::demangle_type<T>(), "'"));
return v;
T OTMLNode::value() {
T ret;
if(!fw::cast(m_value, ret))
throw OTMLException(shared_from_this(), fw::mkstr("failed to cast node value to type '", fw::demangle_type<T>(), "'"));
return ret;
}
template<typename T>
T OTMLNode::read(const T& def) {
if(hasValue())
return read<T>();
T OTMLNode::valueAt(const std::string& childTag) {
OTMLNodePtr node = at(childTag);
return node->value<T>();
}
template<typename T>
T OTMLNode::valueAtIndex(int childIndex) {
OTMLNodePtr node = atIndex(childIndex);
return node->value<T>();
}
template<typename T>
T OTMLNode::valueAt(const std::string& childTag, const T& def) {
if(OTMLNodePtr node = get(childTag))
if(!node->isNull())
return node->value<T>();
return def;
}
template<typename T, typename U>
T OTMLNode::readAt(const U& childIdentifier) {
OTMLNodePtr child = at(childIdentifier);
return child->read<T>();
template<typename T>
T OTMLNode::valueAtIndex(int childIndex, const T& def) {
if(OTMLNodePtr node = getIndex(childIndex))
return node->value<T>();
return def;
}
template<typename T, typename U>
T OTMLNode::readAt(const U& childIdentifier, const T& def) {
OTMLNodePtr child = get(childIdentifier);
if(!child)
return def;
return child->read<T>(def);
}
// templates for writing values
template<typename T>
void OTMLNode::write(const T& v) {
to_otmlnode(shared_from_this(), v);
m_value = fw::safe_cast<std::string>(v);
}
template<typename T>
void OTMLNode::writeAt(const std::string& childTag, const T& v) {
OTMLNodePtr child = get(childTag);
bool created = false;
if(!child) {
child = OTMLNodePtr(new OTMLNode);
child->setTag(childTag);
child->setUnique();
created = true;
}
child->write<T>(v);
if(created)
addChild(child);
}
template<typename T>
void OTMLNode::writeIn(const T& v) {
OTMLNodePtr child = OTMLNodePtr(new OTMLNode);
OTMLNodePtr child = OTMLNode::create(childTag);
child->write<T>(v);
addChild(child);
}
// templates for casting a node to another type
template<typename T>
bool from_otmlnode(OTMLNodePtr node, T& v) {
return fw::cast(node->value(), v);
}
template<typename T>
bool from_otmlnode(OTMLNodePtr node, std::vector<T>& v) {
v.resize(node->size());
for(unsigned i=0;i<node->size();++i)
v[i] = node->readAt<T>(i);
return true;
}
template<typename T>
bool from_otmlnode(OTMLNodePtr node, std::list<T>& v) {
for(unsigned i=0;i<node->size();++i)
v.push_back(node->readAt<T>(i));
return true;
}
template <typename K, typename T>
bool from_otmlnode(OTMLNodePtr node, std::map<K, T>& m) {
for(int i=0;i<node->size();++i) {
K k;
if(!fw::cast(node->at(i)->tag(), k))
return false;
m[k] = node->at(i)->read<T>();
}
return true;
}
// templates for casting a type to a node
template<typename T>
void to_otmlnode(OTMLNodePtr node, const T& v) {
node->setValue(fw::unsafe_cast<std::string>(v));
}
template<typename T>
void to_otmlnode(OTMLNodePtr node, const std::vector<T>& v) {
for(unsigned i=0;i<v.size();++i) {
OTMLNodePtr newNode(new OTMLNode);
newNode->write(v[i]);
node->addChild(newNode);
}
}
template<typename T>
void to_otmlnode(OTMLNodePtr node, const std::list<T>& v) {
for(unsigned i=0;i<v.size();++i) {
OTMLNodePtr newNode(new OTMLNode);
newNode->write(v[i]);
node->addChild(newNode);
}
}
template <typename K, typename T>
void to_otmlnode(OTMLNodePtr node, const std::map<K, T>& m) {
for(auto it = m.begin(); it != m.end(); ++it) {
std::string k = fw::unsafe_cast<std::string>(it->first);
OTMLNodePtr newNode(new OTMLNode);
newNode->setTag(k);
newNode->setUnique();
newNode->write(it->second);
node->addChild(newNode);
}
void OTMLNode::writeIn(const T& v) {
OTMLNodePtr child = OTMLNode::create();
child->write<T>(v);
addChild(child);
}
#endif

View File

@@ -1,5 +1,6 @@
#include "otmlparser.h"
#include "otmldocument.h"
#include "otmlexception.h"
OTMLParser::OTMLParser(OTMLDocumentPtr doc, std::istream& in) :
currentDepth(0), currentLine(0),
@@ -52,6 +53,9 @@ void OTMLParser::parseLine(std::string line)
{
int depth = getLineDepth(line);
if(depth == -1)
return;
// remove line sides spaces
boost::trim(line);
@@ -87,6 +91,7 @@ void OTMLParser::parseNode(const std::string& data)
std::string tag;
std::string value;
std::size_t dotsPos = data.find_first_of(':');
int nodeLine = currentLine;
// node that has no tag and may have a value
if(!data.empty() && data[0] == '-') {
@@ -150,11 +155,18 @@ void OTMLParser::parseNode(const std::string& data)
}
// create the node
OTMLNodePtr node(new OTMLNode);
OTMLNodePtr node = OTMLNode::create(tag);
node->setUnique(dotsPos != std::string::npos);
node->setTag(tag);
node->setValue(value);
node->setSource(doc->source() + ":" + fw::safe_cast<std::string>(currentLine));
node->setSource(doc->source() + ":" + fw::unsafe_cast<std::string>(nodeLine));
// ~ is considered the null value
if(value == "~")
node->setNull(true);
else
node->setValue(value);
currentParent->addChild(node);
previousNode = node;
}