#ifndef JEZUK_SimpleDOM_DOCUMENTIMPL_H #define JEZUK_SimpleDOM_DOCUMENTIMPL_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace SimpleDOM { template class valueIs : public std::unary_function*, bool> { public: valueIs(const stringT& value) : value_(value) { } bool operator()(const AttrImpl* node) const { return (node->getNodeValue() == value_); } // operator() private: stringT value_; }; // class valueIs template class DocumentImpl : public DOM::Document_impl, public NodeImplWithChildren { typedef NodeImpl NodeImplT; typedef AttrImpl AttrImplT; typedef NodeImplWithChildren NodeWithChildrenT; public: DocumentImpl() : NodeImplWithChildren(0), documentElement_(0), documentType_(0), domImplementation_(), namespaceURI_(), qualifiedName_(), changesCount_(0), refCount_(0), empty_() { NodeImplT::setOwnerDoc(this); } // DocumentBaseImpl DocumentImpl(DOM::DOMImplementation domImpl) : NodeImplWithChildren(0), documentElement_(0), documentType_(0), domImplementation_(domImpl), namespaceURI_(), qualifiedName_(), changesCount_(0), refCount_(0) { NodeImplT::setOwnerDoc(this); } // DocumentBaseImpl DocumentImpl(const stringT& namespaceURI, const stringT& qualifiedName, DOM::DocumentType_impl* docType, DOM::DOMImplementation domImpl) : NodeImplWithChildren(0), documentElement_(0), documentType_(0), domImplementation_(domImpl), namespaceURI_(namespaceURI), qualifiedName_(qualifiedName), changesCount_(0), refCount_(0) { NodeImplT::setOwnerDoc(this); if(docType) { if(docType->getOwnerDocument() != 0) throw DOM::DOMException(DOM::DOMException::WRONG_DOCUMENT_ERR); appendChild(docType); } // if(docType) } // DocumentBaseImpl virtual ~DocumentImpl() { for(typename std::set::iterator n = orphans_.begin(); n != orphans_.end(); ++n) delete *n; } // ~DocumentImpl ///////////////////////////////////////////////////////////////////// // Ref counting virtual void addRef() { ++refCount_; } // addRef virtual void releaseRef() { if(--refCount_ == 0) delete this; } // releaseRef ///////////////////////////////////////////////////////////////////// // DOM::Document functions virtual DOM::DocumentType_impl* getDoctype() const { return documentType_; } // getDocType virtual DOM::DOMImplementation getImplementation() const { return domImplementation_; } // getImplementation virtual DOM::Element_impl* getDocumentElement() const { return documentElement_; } // getDocumentElement virtual DOM::Element_impl* createElement(const stringT& tagName) const { ElementImpl* n = new ElementImpl(const_cast(this), tagName); orphaned(n); return n; } // createElement virtual DOM::DocumentFragment_impl* createDocumentFragment() const { DocumentFragmentImpl* n = new DocumentFragmentImpl(const_cast(this)); orphaned(n); return n; } // createDocumentFragment virtual DOM::Text_impl* createTextNode(const stringT& data) const { TextImpl* n = new TextImpl(const_cast(this), data); orphaned(n); return n; } // createTextNode virtual DOM::Comment_impl* createComment(const stringT& data) const { CommentImpl* n = new CommentImpl(const_cast(this), data); orphaned(n); return n; } // createComment virtual DOM::CDATASection_impl* createCDATASection(const stringT& data) const { CDATASectionImpl* n = new CDATASectionImpl(const_cast(this), data); orphaned(n); return n; } // createCDATASection virtual DOM::ProcessingInstruction_impl* createProcessingInstruction(const stringT& target, const stringT& data) const { ProcessingInstructionImpl* n = new ProcessingInstructionImpl(const_cast(this), target, data); orphaned(n); return n; } // createProcessingInstruction virtual DOM::Attr_impl* createAttribute(const stringT& name) const { AttrImpl* n = new AttrImpl(const_cast(this), name); orphaned(n); return n; } // createAttribute virtual DOM::EntityReference_impl* createEntityReference(const stringT& name) const { EntityReferenceImpl* n = new EntityReferenceImpl(const_cast(this), name); if((documentType_ != 0) && (documentType_->getEntities()->getNamedItem(name) != 0)) { DOM::Node_impl* entity = documentType_->getEntities()->getNamedItem(name); for(DOM::Node_impl* child = entity->getFirstChild(); child != 0; child = child->getNextSibling()) n->appendChild(importNode(child, true)); } // if ... orphaned(n); n->setReadOnly(true); return n; } // createEntityReference virtual DOM::NodeList_impl* getElementsByTagName(const stringT& tagname) const { return new ElementByTagList(const_cast(this), const_cast(this), tagname); } // getElementsByTagName virtual DOM::Node_impl* importNode(DOM::Node_impl* importedNode, bool deep) const { DOM::Node_impl* newNode = 0; switch(importedNode->getNodeType()) { case DOM::Node::ATTRIBUTE_NODE: if(string_adaptorT::empty(importedNode->getLocalName())) newNode = createAttribute(importedNode->getNodeName()); else newNode = createAttributeNS(importedNode->getNamespaceURI(), importedNode->getNodeName()); deep = true; break; case DOM::Node::DOCUMENT_FRAGMENT_NODE: newNode = createDocumentFragment(); break; case DOM::Node::DOCUMENT_NODE: throw DOM::DOMException(DOM::DOMException::NOT_SUPPORTED_ERR); case DOM::Node::DOCUMENT_TYPE_NODE: throw DOM::DOMException(DOM::DOMException::NOT_SUPPORTED_ERR); case DOM::Node::ELEMENT_NODE: { DOM::Element_impl* elem; if(string_adaptorT::empty(importedNode->getLocalName())) elem = createElement(importedNode->getNodeName()); else elem = createElementNS(importedNode->getNamespaceURI(), importedNode->getNodeName()); const DOM::NamedNodeMap_impl* attrs = importedNode->getAttributes(); if(attrs) for(unsigned int i = 0; i < attrs->getLength(); ++i) { DOM::Attr_impl* a = dynamic_cast*>(attrs->item(i)); if(a->getSpecified()) { DOM::Attr_impl* newA = dynamic_cast*>(importNode(a, true)); if(string_adaptorT::empty(a->getLocalName())) elem->setAttributeNode(newA); else elem->setAttributeNodeNS(newA); } // if ... } // for newNode = elem; } break; case DOM::Node::ENTITY_NODE: { DOM::Entity_impl* entity = dynamic_cast*>(importedNode); newNode = new EntityImpl(const_cast(this), entity->getNodeName(), entity->getPublicId(), entity->getSystemId(), entity->getNotationName()); } break; case DOM::Node::ENTITY_REFERENCE_NODE: newNode = createEntityReference(importedNode->getNodeName()); deep = false; break; case DOM::Node::NOTATION_NODE: { DOM::Notation_impl* entity = dynamic_cast*>(importedNode); newNode = new NotationImpl(const_cast(this), entity->getNodeName(), entity->getPublicId(), entity->getSystemId()); } break; case DOM::Node::PROCESSING_INSTRUCTION_NODE: newNode = createProcessingInstruction(importedNode->getNodeName(), importedNode->getNodeValue()); break; case DOM::Node::TEXT_NODE: newNode = createTextNode(importedNode->getNodeValue()); break; case DOM::Node::CDATA_SECTION_NODE: newNode = createCDATASection(importedNode->getNodeValue()); break; case DOM::Node::COMMENT_NODE: newNode = createComment(importedNode->getNodeValue()); break; default: throw std::runtime_error("Bad node type value in importNode"); } // switch if(deep) { for(DOM::Node_impl* child = importedNode->getFirstChild(); child != 0; child = child->getNextSibling()) newNode->appendChild(importNode(child, true)); } // if(deep) if(newNode->getNodeType() == DOM::Node::ENTITY_NODE) dynamic_cast(newNode)->setReadOnly(true); orphaned(dynamic_cast(newNode)); return newNode; } // importNode virtual DOM::Element_impl* createElementNS(const stringT& namespaceURI, const stringT& qualifiedName) const { ElementNSImpl* n = new ElementNSImpl(const_cast(this), namespaceURI, !string_adaptorT::empty(namespaceURI), qualifiedName); orphaned(n); return n; } // createElementNS virtual DOM::Attr_impl* createAttributeNS(const stringT& namespaceURI, const stringT& qualifiedName) const { AttrNSImpl* n = new AttrNSImpl(const_cast(this), namespaceURI, !string_adaptorT::empty(namespaceURI), qualifiedName); orphaned(n); return n; } // createAttrNS virtual DOM::NodeList_impl* getElementsByTagNameNS(const stringT& namespaceURI, const stringT& localName) const { return new ElementByTagList(const_cast(this), const_cast(this), namespaceURI, localName); } // getElementsByTagNameNS virtual DOM::Element_impl* getElementById(const stringT& elementId) const { typename std::set::const_iterator i = std::find_if(idNodes_.begin(), idNodes_.end(), valueIs(elementId)); if(i == idNodes_.end()) return 0; return (*i)->getOwnerElement(); } // getElementById //////////////////////////////////////////////////////// // DOM Node methods virtual typename DOM::Node::Type getNodeType() const { return DOM::Node::DOCUMENT_NODE; } // getNodeType virtual DOM::Node_impl* getParentNode() const { return 0; } virtual DOM::Document_impl* getOwnerDocument() const { return 0; } virtual const stringT& getNodeName() const { static const stringT doc = string_adaptorT::construct_from_utf8("#document"); return doc; } // getNodeName virtual DOM::Node_impl* insertBefore(DOM::Node_impl* newChild, DOM::Node_impl* refChild) { if((newChild->getNodeType() == DOM::Node::ELEMENT_NODE) && (documentElement_ != 0)) throw DOM::DOMException(DOM::DOMException::HIERARCHY_REQUEST_ERR); if((newChild->getNodeType() == DOM::Node::DOCUMENT_TYPE_NODE) && (documentType_ != 0)) throw DOM::DOMException(DOM::DOMException::HIERARCHY_REQUEST_ERR); DOM::Node_impl* result = NodeImplWithChildren::insertBefore(newChild, refChild); if((newChild->getNodeType() == DOM::Node::ELEMENT_NODE) && (documentElement_ == 0)) documentElement_ = dynamic_cast*>(newChild); if((newChild->getNodeType() == DOM::Node::DOCUMENT_TYPE_NODE) && (documentType_ == 0)) documentType_ = dynamic_cast*>(newChild); return result; } // insertBefore virtual DOM::Node_impl* replaceChild(DOM::Node_impl* newChild, DOM::Node_impl* oldChild) { checkChildType(newChild); if((newChild->getNodeType() == DOM::Node::DOCUMENT_TYPE_NODE) && (documentType_ == oldChild)) throw DOM::DOMException(DOM::DOMException::HIERARCHY_REQUEST_ERR); if((newChild->getNodeType() == DOM::Node::ELEMENT_NODE) && (documentElement_ != 0) && (documentElement_ != oldChild)) throw DOM::DOMException(DOM::DOMException::HIERARCHY_REQUEST_ERR); DOM::Node_impl* result = NodeImplWithChildren::replaceChild(newChild, oldChild); if((newChild->getNodeType() == DOM::Node::ELEMENT_NODE) && ((documentElement_ == 0) || (documentElement_ == oldChild))) documentElement_ = dynamic_cast*>(newChild); return result; } // replaceChild virtual DOM::Node_impl* removeChild(DOM::Node_impl* oldChild) { if((documentType_ == oldChild)) throw DOM::DOMException(DOM::DOMException::HIERARCHY_REQUEST_ERR); DOM::Node_impl* result = NodeImplWithChildren::removeChild(oldChild); if(documentElement_ == oldChild) documentElement_ = static_cast*>(0); return result; } // removeChild virtual DOM::Node_impl* appendChild(DOM::Node_impl* newChild) { return insertBefore(newChild, 0); } // appendChild virtual DOM::Node_impl* cloneNode(bool deep) const { DocumentImpl* clone = new DocumentImpl(namespaceURI_, qualifiedName_, 0, domImplementation_); if(documentType_ != 0) { DocumentTypeImpl* dt = dynamic_cast*>(documentType_->cloneNode(true)); dt->setOwnerDoc(clone); clone->appendChild(dt); } if(deep) for(DOM::Node_impl* child = NodeWithChildrenT::getFirstChild(); child != 0; child = child->getNextSibling()) if((documentType_ != child) && (child != clone->getDocumentElement())) clone->appendChild(clone->importNode(child, true)); return clone; } // cloneNode //////////////////////////// // extensions void markChanged() { ++changesCount_; } unsigned long changes() const { return changesCount_; } void orphaned(NodeImplT* node) const { orphans_.insert(node); } // orphaned void purge(NodeImplT* node) { orphans_.erase(node); delete node; } // purge void adopted(NodeImplT* node) { typename std::set::iterator n = orphans_.find(node); if(n != orphans_.end()) orphans_.erase(n); } // adopted void setElementId(AttrImplT* attr) { idNodes_.insert(attr); } // setElementId void removeElementId(AttrImplT* attr) { typename std::set::iterator n = idNodes_.find(attr); if(n != idNodes_.end()) idNodes_.erase(n); } // removeElementId stringT const* const stringPool(const stringT& str) const { typename std::list::const_iterator i = std::find(stringPool_.begin(), stringPool_.end(), str); if(i != stringPool_.end()) return &(*i); stringPool_.push_back(str); return &(stringPool_.back()); } // stringPool const stringT& empty_string() const { return empty_; } private: void checkChildType(typename DOM::Node_impl* child) { typename DOM::Node::Type type = child->getNodeType(); if((type != DOM::Node::ELEMENT_NODE) && (type != DOM::Node::PROCESSING_INSTRUCTION_NODE) && (type != DOM::Node::COMMENT_NODE) && (type != DOM::Node::DOCUMENT_TYPE_NODE)) throw DOM::DOMException(DOM::DOMException::HIERARCHY_REQUEST_ERR); } // checkChildType private: DOM::Element_impl* documentElement_; DOM::DocumentType_impl* documentType_; DOM::DOMImplementation domImplementation_; stringT namespaceURI_; stringT qualifiedName_; unsigned long changesCount_; unsigned long refCount_; mutable std::set orphans_; std::set idNodes_; mutable std::list stringPool_; const stringT empty_; }; // class DocumentImpl } // namespace SAX2DOM #endif // end of file