/* * Copyright (c) 2010-2012 OTClient * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "otmlnode.h" #include "otmlemitter.h" #include "otmldocument.h" OTMLNodePtr OTMLNode::create(std::string tag, bool unique) { OTMLNodePtr node(new OTMLNode); node->setTag(tag); node->setUnique(unique); return node; } OTMLNodePtr OTMLNode::create(std::string tag, std::string value) { OTMLNodePtr node(new OTMLNode); node->setTag(tag); node->setValue(value); node->setUnique(true); return node; } bool OTMLNode::hasChildren() const { int count = 0; for(const OTMLNodePtr& child : m_children) { if(!child->isNull()) count++; } return count > 0; } OTMLNodePtr OTMLNode::get(const std::string& childTag) const { for(const OTMLNodePtr& child : m_children) { if(child->tag() == childTag && !child->isNull()) return child; } return nullptr; } OTMLNodePtr OTMLNode::getIndex(int childIndex) const { if(childIndex < size() && childIndex >= 0) 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(const OTMLNodePtr& node : m_children) { if(node->tag() == newChild->tag() && (node->isUnique() || newChild->isUnique())) { newChild->setUnique(true); if(node->hasChildren() && newChild->hasChildren()) { OTMLNodePtr tmpNode = node->clone(); tmpNode->merge(newChild); newChild->copy(tmpNode); } replaceChild(node, newChild); // remove any other child with the same tag 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_children.erase(it); } else ++it; } return; } } } m_children.push_back(newChild); newChild->setParent(shared_from_this()); } bool OTMLNode::removeChild(const OTMLNodePtr& oldChild) { 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) { 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::copy(const OTMLNodePtr& node) { setTag(node->tag()); setValue(node->value()); setUnique(node->isUnique()); setNull(node->isNull()); setSource(node->source()); clear(); for(const OTMLNodePtr& child : node->m_children) addChild(child->clone()); } void OTMLNode::merge(const OTMLNodePtr& node) { 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(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; } std::string OTMLNode::emit() { return OTMLEmitter::emitNode(shared_from_this(), 0); }