#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 namespace Arabica { namespace SimpleDOM { template class valueIs { public: explicit 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 ElementImpl ElementImplT; typedef NodeImplWithChildren NodeWithChildrenT; public: typedef DOM::Node_impl DOMNode_implT; typedef DOM::Attr_impl DOMAttr_implT; typedef DOM::Element_impl DOMElement_implT; typedef DOM::Document_impl DOMDocument_implT; typedef DOM::DocumentType_impl DOMDocumentType_implT; typedef DOM::DOMImplementation DOMDOMImplementationT; DocumentImpl() : NodeWithChildrenT(0), documentElement_(0), documentType_(0), domImplementation_(), namespaceURI_(), qualifiedName_(), changesCount_(0), refCount_(0), empty_() { NodeImplT::setOwnerDoc(this); } // DocumentBaseImpl DocumentImpl(DOMDOMImplementationT domImpl) : NodeWithChildrenT(0), documentElement_(0), documentType_(0), domImplementation_(domImpl), namespaceURI_(), qualifiedName_(), changesCount_(0), refCount_(0) { NodeImplT::setOwnerDoc(this); } // DocumentBaseImpl DocumentImpl(const stringT& namespaceURI, const stringT& qualifiedName, DOMDocumentType_implT* docType, DOMDOMImplementationT domImpl) : NodeWithChildrenT(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 DOMDocumentType_implT* getDoctype() const { return documentType_; } // getDocType virtual DOMDOMImplementationT getImplementation() const { return domImplementation_; } // getImplementation virtual DOMElement_implT* getDocumentElement() const { return documentElement_; } // getDocumentElement virtual DOMElement_implT* createElement(const stringT& tagName) const { this->checkName(tagName); return createElement_nocheck(tagName); } // createElement DOMElement_implT* createElement_nocheck(const stringT& tagName) const { ElementImplT* n = new ElementImplT(const_cast(this), tagName); orphaned(n); return n; } // createElement_nocheck 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 { this->checkName(target); this->checkChars(data); return createProcessingInstruction_nocheck(target, data); } // createProcessingInstruction DOM::ProcessingInstruction_impl* createProcessingInstruction_nocheck(const stringT& target, const stringT& data) const { ProcessingInstructionImpl* n = new ProcessingInstructionImpl(const_cast(this), target, data); orphaned(n); return n; } // createProcessingInstruction_nocheck virtual DOMAttr_implT* createAttribute(const stringT& name) const { this->checkName(name); return createAttribute_nocheck(name); } // createAttribute DOMAttr_implT* createAttribute_nocheck(const stringT& name) const { AttrImpl* n = new AttrImpl(const_cast(this), name); orphaned(n); return n; } // createAttribute_nocheck virtual DOM::EntityReference_impl* createEntityReference(const stringT& name) const { this->checkName(name); return createEntityReference_nocheck(name); } // createEntityRef DOM::EntityReference_impl* createEntityReference_nocheck(const stringT& name) const { EntityReferenceImpl* n = new EntityReferenceImpl(const_cast(this), name); if((documentType_ != 0) && (documentType_->getEntities()->getNamedItem(name) != 0)) { DOMNode_implT* entity = documentType_->getEntities()->getNamedItem(name); for(DOMNode_implT* 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 DOMNode_implT* importNode(DOMNode_implT* importedNode, bool deep) const { DOMNode_implT* newNode = 0; switch(importedNode->getNodeType()) { case DOM::Node_base::ATTRIBUTE_NODE: if(string_adaptorT::empty(importedNode->getLocalName())) newNode = createAttribute_nocheck(importedNode->getNodeName()); else newNode = createAttributeNS_nocheck(importedNode->getNamespaceURI(), importedNode->getNodeName()); deep = true; break; case DOM::Node_base::DOCUMENT_FRAGMENT_NODE: newNode = createDocumentFragment(); break; case DOM::Node_base::DOCUMENT_NODE: throw DOM::DOMException(DOM::DOMException::NOT_SUPPORTED_ERR); case DOM::Node_base::DOCUMENT_TYPE_NODE: throw DOM::DOMException(DOM::DOMException::NOT_SUPPORTED_ERR); case DOM::Node_base::ELEMENT_NODE: { DOMElement_implT* elem; if(string_adaptorT::empty(importedNode->getLocalName())) elem = createElement_nocheck(importedNode->getNodeName()); else elem = createElementNS_nocheck(importedNode->getNamespaceURI(), importedNode->getNodeName()); const DOM::NamedNodeMap_impl* attrs = importedNode->getAttributes(); if(attrs) for(unsigned int i = 0; i < attrs->getLength(); ++i) { DOMAttr_implT* a = dynamic_cast(attrs->item(i)); if(a->getSpecified()) { DOMAttr_implT* 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_base::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_base::ENTITY_REFERENCE_NODE: newNode = createEntityReference_nocheck(importedNode->getNodeName()); deep = false; break; case DOM::Node_base::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_base::PROCESSING_INSTRUCTION_NODE: newNode = createProcessingInstruction_nocheck(importedNode->getNodeName(), importedNode->getNodeValue()); break; case DOM::Node_base::TEXT_NODE: newNode = createTextNode(importedNode->getNodeValue()); break; case DOM::Node_base::CDATA_SECTION_NODE: newNode = createCDATASection(importedNode->getNodeValue()); break; case DOM::Node_base::COMMENT_NODE: newNode = createComment(importedNode->getNodeValue()); break; default: throw std::runtime_error("Bad node type value in importNode"); } // switch if(deep) { for(DOMNode_implT* child = importedNode->getFirstChild(); child != 0; child = child->getNextSibling()) newNode->appendChild(importNode(child, true)); } // if(deep) if(newNode->getNodeType() == DOM::Node_base::ENTITY_NODE) dynamic_cast(newNode)->setReadOnly(true); orphaned(dynamic_cast(newNode)); return newNode; } // importNode virtual DOMElement_implT* createElementNS(const stringT& namespaceURI, const stringT& qualifiedName) const { this->checkName(qualifiedName); return createElementNS_nocheck(namespaceURI, qualifiedName); } // createElementNS DOMElement_implT* createElementNS_nocheck(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 DOMAttr_implT* createAttributeNS(const stringT& namespaceURI, const stringT& qualifiedName) const { this->checkName(qualifiedName); return createAttributeNS_nocheck(namespaceURI, qualifiedName); } // createAttributeNS virtual DOMAttr_implT* createAttributeNS_nocheck(const stringT& namespaceURI, const stringT& qualifiedName) const { AttrNSImpl* n = new AttrNSImpl(const_cast(this), namespaceURI, !string_adaptorT::empty(namespaceURI), qualifiedName); orphaned(n); return n; } // createAttributeNS_nocheck 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 DOMElement_implT* 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_base::Type getNodeType() const { return DOM::Node_base::DOCUMENT_NODE; } // getNodeType virtual DOMNode_implT* getParentNode() const { return 0; } virtual DOMDocument_implT* getOwnerDocument() const { return 0; } virtual const stringT& getNodeName() const { static const stringT doc = string_adaptorT::construct_from_utf8("#document"); return doc; } // getNodeName virtual DOMNode_implT* insertBefore(DOMNode_implT* newChild, DOMNode_implT* refChild) { if((newChild->getNodeType() == DOM::Node_base::ELEMENT_NODE) && (documentElement_ != 0)) throw DOM::DOMException(DOM::DOMException::HIERARCHY_REQUEST_ERR); if((newChild->getNodeType() == DOM::Node_base::DOCUMENT_TYPE_NODE) && (documentType_ != 0)) throw DOM::DOMException(DOM::DOMException::HIERARCHY_REQUEST_ERR); DOMNode_implT* result = NodeWithChildrenT::insertBefore(newChild, refChild); if((newChild->getNodeType() == DOM::Node_base::ELEMENT_NODE) && (documentElement_ == 0)) documentElement_ = dynamic_cast(newChild); if((newChild->getNodeType() == DOM::Node_base::DOCUMENT_TYPE_NODE) && (documentType_ == 0)) documentType_ = dynamic_cast(newChild); return result; } // insertBefore virtual DOMNode_implT* replaceChild(DOMNode_implT* newChild, DOMNode_implT* oldChild) { checkChildType(newChild); if((newChild->getNodeType() == DOM::Node_base::DOCUMENT_TYPE_NODE) && (documentType_ == oldChild)) throw DOM::DOMException(DOM::DOMException::HIERARCHY_REQUEST_ERR); if((newChild->getNodeType() == DOM::Node_base::ELEMENT_NODE) && (documentElement_ != 0) && (documentElement_ != oldChild)) throw DOM::DOMException(DOM::DOMException::HIERARCHY_REQUEST_ERR); DOMNode_implT* result = NodeWithChildrenT::replaceChild(newChild, oldChild); if((newChild->getNodeType() == DOM::Node_base::ELEMENT_NODE) && ((documentElement_ == 0) || (documentElement_ == oldChild))) documentElement_ = dynamic_cast(newChild); return result; } // replaceChild virtual DOMNode_implT* removeChild(DOMNode_implT* oldChild) { if(documentType_ == oldChild) throw DOM::DOMException(DOM::DOMException::HIERARCHY_REQUEST_ERR); DOMNode_implT* result = NodeWithChildrenT::removeChild(oldChild); if(documentElement_ == oldChild) documentElement_ = static_cast(0); return result; } // removeChild virtual DOMNode_implT* appendChild(DOMNode_implT* newChild) { return insertBefore(newChild, 0); } // appendChild virtual DOMNode_implT* 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(DOMNode_implT* 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 bool isOrphaned(NodeImplT* node) const { return orphans_.find(node) != orphans_.end(); } // isOrphaned 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* stringPool(const stringT& str) const { return &(*stringPool_.insert(str).first); } // stringPool const stringT& empty_string() const { return empty_; } private: void checkChildType(DOMNode_implT* child) { typename DOM::Node_base::Type type = child->getNodeType(); if((type != DOM::Node_base::ELEMENT_NODE) && (type != DOM::Node_base::PROCESSING_INSTRUCTION_NODE) && (type != DOM::Node_base::COMMENT_NODE) && (type != DOM::Node_base::DOCUMENT_TYPE_NODE)) throw DOM::DOMException(DOM::DOMException::HIERARCHY_REQUEST_ERR); } // checkChildType private: DOMElement_implT* documentElement_; DOMDocumentType_implT* documentType_; DOMDOMImplementationT domImplementation_; stringT namespaceURI_; stringT qualifiedName_; unsigned long changesCount_; unsigned long refCount_; mutable std::set orphans_; std::set idNodes_; mutable std::set stringPool_; const stringT empty_; }; // class DocumentImpl } // namespace SAX2DOM } // namespace Arabica #endif // end of file