You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

226 lines
4.9 KiB

#include "otmlnode.h"
#include "otmlemitter.h"
#include "otmldocument.h"
OTMLNode::OTMLNode()
{
m_unique = false;
}
std::string OTMLNode::tag() const
{
return m_tag;
}
std::string OTMLNode::value() 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;
}
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;
}
OTMLNodePtr OTMLNode::get(const std::string& childTag) const
{
for(const OTMLNodePtr& child : m_childNodes) {
if(child->tag() == childTag)
return child;
}
return nullptr;
}
OTMLNodePtr OTMLNode::get(int childIndex) const
{
if(childIndex < size() && childIndex >= 0)
return m_childNodes[childIndex];
return nullptr;
}
void OTMLNode::addChild(const OTMLNodePtr& newChild)
{
// replace is needed when the tag is marked as unique
if(newChild->hasTag()) {
for(OTMLNodePtr node : m_childNodes) {
if(node->tag() == newChild->tag() && (node->isUnique() || newChild->isUnique())) {
newChild->setUnique();
replaceChild(node, newChild);
// remove any other child with the same tag
auto it = m_childNodes.begin();
while(it != m_childNodes.end()) {
OTMLNodePtr node = (*it);
if(node != newChild && node->tag() == newChild->tag()) {
node->setParent(nullptr);
it = m_childNodes.erase(it);
} else
++it;
}
return;
}
}
}
m_childNodes.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;
}
}
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;
}
}
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);
}
}
OTMLNodePtr OTMLNode::clone() const
{
OTMLNodePtr myClone(new OTMLNode);
myClone->setTag(tag());
myClone->setValue(value());
myClone->setUnique(isUnique());
for(OTMLNodePtr child : childNodes())
myClone->addChild(child->clone());
return myClone;
}
std::string OTMLNode::emit()
{
return OTMLEmitter::emitNode(shared_from_this(), 0);
}