/** * Phoebe DOM Implementation. * * This is a C++ approximation of the W3C DOM model, which follows * fairly closely the specifications in the various .idl files, copies of * which are provided for reference. Most important is this one: * * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html * * Authors: * Bob Jamison * * Copyright (C) 2005 Bob Jamison * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "domimpl.h" namespace org { namespace w3c { namespace dom { /** * Test if the given substring exists for the length of the string * in a given buffer */ /* static bool match(const DOMString &buf, char *str) { int pos = 0; while (*str) { if (buf[pos++] != *str++) return false; } return true; } */ /*######################################################################### ## DOMImplementationSourceImpl #########################################################################*/ /** * */ DOMImplementationSourceImpl::DOMImplementationSourceImpl() { domImpl = new DOMImplementationImpl(); } /** * */ DOMImplementationSourceImpl::~DOMImplementationSourceImpl() { delete domImpl; } /** * */ DOMImplementation *DOMImplementationSourceImpl::getDOMImplementation( const DOMString &features) { return domImpl; } /** * */ DOMImplementationList DOMImplementationSourceImpl::getDOMImplementationList( const DOMString &features) { return domImplList; } /*######################################################################### ## DOMImplementationImpl #########################################################################*/ /** * */ DOMImplementationImpl::DOMImplementationImpl() { } /** * */ DOMImplementationImpl::~DOMImplementationImpl() { } /** * */ bool DOMImplementationImpl::hasFeature(const DOMString& feature, const DOMString& version) { return false; } /** * */ DocumentTypePtr DOMImplementationImpl::createDocumentType(const DOMString& qualifiedName, const DOMString& publicId, const DOMString& systemId) throw(DOMException) { DocumentTypePtr typeImpl = new DocumentTypeImpl(qualifiedName, publicId, systemId); return typeImpl; } /** * */ DocumentPtr DOMImplementationImpl::createDocument( const DOMString& namespaceURI, const DOMString& qualifiedName, DocumentTypePtr doctype) throw(DOMException) { DocumentPtr doc = new DocumentImpl(this, namespaceURI, qualifiedName, doctype); return doc; } /** * */ DOMObject *DOMImplementationImpl::getFeature(const DOMString& feature, const DOMString& version) { return NULL; } /*######################################################################### ## NodeImpl #########################################################################*/ /** * Utility for finding the first Element above * a given node. Used by several methods below */ static NodePtr getAncestorElement(NodePtr node) { if (!node.get()) return NULL; node = node->getParentNode(); //Either quit because I am an element, or because I am null while (node.get()) { if (node->getNodeType() == Node::ELEMENT_NODE) return node; node = node->getParentNode(); } return node; } /** * */ DOMString NodeImpl::getNodeName() { return nodeName; } /** * */ DOMString NodeImpl::getNodeValue() throw (DOMException) { return nodeValue; } /** * */ void NodeImpl::setNodeValue(const DOMString& val) throw (DOMException) { nodeValue = val; } /** * */ unsigned short NodeImpl::getNodeType() { return nodeType; } /** * */ NodePtr NodeImpl::getParentNode() { return parent; } /** * */ NodeList NodeImpl::getChildNodes() { NodeList list; for (NodeImplPtr node = firstChild ; node.get() ; node=node->next) list.add(node); return list; } /** * */ NodePtr NodeImpl::getFirstChild() { return firstChild; } /** * */ NodePtr NodeImpl::getLastChild() { return lastChild; } /** * */ NodePtr NodeImpl::getPreviousSibling() { return prev; } /** * */ NodePtr NodeImpl::getNextSibling() { return next; } /** * */ NamedNodeMap &NodeImpl::getAttributes() { NamedNodeMap &attrs = attributes; return attrs; } /** * */ DocumentPtr NodeImpl::getOwnerDocument() { return ownerDocument; } /** * */ NodePtr NodeImpl::insertBefore(const NodePtr newChild, const NodePtr refChild) throw(DOMException) { if (!newChild) return NULL; //if no ref, then just append if (!refChild) return appendChild(newChild); NodeImplPtr newChildImpl = dynamic_cast(newChild.get()); for (NodeImplPtr n = firstChild ; n.get() ; n=n->next) { if (n == refChild) { //link to new if (n->prev.get()) n->prev->next = newChildImpl; else firstChild = newChildImpl; n->prev = newChildImpl; //link from new newChildImpl->next = n; newChildImpl->prev = n->prev; //reflect new location newChildImpl->parent = this; newChildImpl->ownerDocument = ownerDocument; return n; } } return NULL; } /** * */ NodePtr NodeImpl::replaceChild(const NodePtr newChild, const NodePtr oldChild) throw(DOMException) { if (!oldChild) return NULL; NodeImplPtr newChildImpl = dynamic_cast(newChild.get()); for (NodeImplPtr n = firstChild ; n.get() ; n=n->next) { if (n == oldChild) { //link to new if (n->prev.get()) n->prev->next = newChildImpl; else firstChild = newChildImpl; if (n->next.get()) n->next->prev = newChildImpl; else lastChild = newChildImpl; //link from new newChildImpl->next = n->next; newChildImpl->prev = n->prev; //reflect new location newChildImpl->parent = this; newChildImpl->ownerDocument = ownerDocument; return n; } } return NULL; } /** * */ NodePtr NodeImpl::removeChild(const NodePtr oldChild) throw(DOMException) { if (!oldChild) return NULL; for (NodeImplPtr n = firstChild ; n.get() ; n=n->next) { if (n == oldChild) { if (n->prev.get()) n->prev->next = n->next; if (n->next.get()) n->next->prev = n->prev; return n; } } return NULL; } /** * */ NodePtr NodeImpl::appendChild(const NodePtr newChild) throw(DOMException) { if (!newChild) return NULL; NodeImplPtr newChildImpl = dynamic_cast (newChild.get()); newChildImpl->parent = this; newChildImpl->ownerDocument = ownerDocument; if (!firstChild || !lastChild) { //Set up our first member firstChild = newChildImpl; lastChild = newChildImpl; } else { //link at the last position lastChild->next = newChildImpl; newChildImpl->prev = lastChild; lastChild = newChildImpl; } return newChild; } /** * */ bool NodeImpl::hasChildNodes() { return (firstChild != (NodeImpl *)0); } /** * */ NodePtr NodeImpl::cloneNode(bool deep) { NodeImplPtr node = new NodeImpl(ownerDocument, nodeName); node->parent = parent; node->prev = prev; node->next = next; node->userData = userData; node->nodeValue = nodeValue; if (deep) { node->firstChild = node->lastChild = NULL; for (NodeImplPtr child = firstChild ; child.get() ; child=child->next) { node->appendChild(child->cloneNode(deep)); } } else { node->firstChild = firstChild; node->lastChild = lastChild; } return node; } /** * Concatenate adjoining text subnodes, remove null-length nodes */ void NodeImpl::normalize() { //First, concatenate adjoining text nodes NodeImplPtr next = (NodeImpl *)0; for (NodeImplPtr child = firstChild ; child.get() ; child=next) { if (child->getNodeType() != Node::TEXT_NODE) continue; next = NULL; DOMString sval = child->getNodeValue(); for (NodeImplPtr sibling = child->next ; sibling.get() ; sibling=next) { next = sibling->next; if (sibling->getNodeType() != Node::TEXT_NODE) break; sval.append(sibling->getNodeValue()); //unlink and delete child->next = sibling->next; if (sibling->next.get()) sibling->next->prev = child; //delete sibling; } child->setNodeValue(sval); } //Next, we remove zero-length text subnodes next = NULL; for (NodeImplPtr child = firstChild ; child.get() ; child=next) { next = child->next; if (child->getNodeType() != Node::TEXT_NODE) continue; if (child->getNodeValue().size() == 0) { //unlink and delete if (child->prev.get()) child->prev->next = child->next; if (child->next.get()) child->next->prev = child->prev; //delete child; } } } /** * */ bool NodeImpl::isSupported(const DOMString& feature, const DOMString& version) { //again, no idea return false; } /** * */ DOMString NodeImpl::getNamespaceURI() { return namespaceURI; } /** * */ DOMString NodeImpl::getPrefix() { return prefix; } /** * */ void NodeImpl::setPrefix(const DOMString& val) throw(DOMException) { prefix = val; if (prefix.size()>0) nodeName = prefix + ":" + localName; else nodeName = localName; } /** * */ DOMString NodeImpl::getLocalName() { return localName; } /** * */ bool NodeImpl::hasAttributes() { return (attributes.getLength() > 0); } /** * */ DOMString NodeImpl::getBaseURI() { return baseURI; } /** * */ unsigned short NodeImpl::compareDocumentPosition(const NodePtr otherArg) { if (!otherArg || otherArg == (NodePtr )this) return 0;//no flags NodePtr node; NodePtr other = otherArg; //Look above me for (node=getParentNode() ; node.get() ; node=node->getParentNode()) if (node == other) return DOCUMENT_POSITION_CONTAINED_BY; //Look above the other guy. See me? for (node=other->getParentNode() ; node.get() ; node=node->getParentNode()) if (node == (NodePtr )this) return DOCUMENT_POSITION_CONTAINS; return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC; } /** * */ DOMString NodeImpl::getTextContent() throw(DOMException) { DOMString buf; if (nodeType == TEXT_NODE || nodeType == CDATA_SECTION_NODE || nodeType == COMMENT_NODE || nodeType == PROCESSING_INSTRUCTION_NODE) buf = getNodeValue(); else if (nodeType == ELEMENT_NODE || nodeType == ATTRIBUTE_NODE || nodeType == ENTITY_NODE || nodeType == ENTITY_REFERENCE_NODE || nodeType == DOCUMENT_FRAGMENT_NODE) { for (NodePtr n = getFirstChild() ; n.get() ; n=n->getNextSibling() ) { if (n->getNodeType() != COMMENT_NODE && n->getNodeType() != COMMENT_NODE) buf.append(n->getTextContent()); } } return buf; } /** * */ void NodeImpl::setTextContent(const DOMString &val) throw(DOMException) { //Delete children /** Not necessary. Just let smart pointers to their work for (NodePtr n = getFirstChild() ; n.get() ; n=n->getNextSibling() ) delete n; */ firstChild = lastChild = NULL; //Replace with a single text node NodeImplPtr tnode = new NodeImpl(ownerDocument); tnode->nodeType = Node::TEXT_NODE; tnode->setNodeValue(val); appendChild(tnode); } /** * From DOM3 Namespace algorithms */ DOMString NodeImpl::lookupPrefix(const DOMString &theNamespaceURI) { if (theNamespaceURI.size()==0) { return DOMString(""); } switch (nodeType) { case Node::ELEMENT_NODE: { ElementPtr elem = (Element *)this; return lookupNamespacePrefix(theNamespaceURI, elem); } case Node::DOCUMENT_NODE: { DocumentPtr doc = (Document *)this; ElementPtr elem = doc->getDocumentElement(); return elem->lookupPrefix(theNamespaceURI); } case Node::ENTITY_NODE : case Node::NOTATION_NODE: case Node::DOCUMENT_FRAGMENT_NODE: case Node::DOCUMENT_TYPE_NODE: return DOMString(""); // type is unknown case Node::ATTRIBUTE_NODE: { AttrPtr attr = (Attr *)this; ElementPtr elem = attr->getOwnerElement(); if ( elem.get() ) { return elem->lookupPrefix(theNamespaceURI); } return DOMString(""); } default: { //Get ancestor element, if any NodePtr ancestor = getAncestorElement(this); if ( ancestor.get() ) { return ancestor->lookupPrefix(theNamespaceURI); } return DOMString(""); } }//switch return DOMString(""); } /** * */ bool NodeImpl::isDefaultNamespace(const DOMString &theNamespaceURI) { switch (nodeType) { case ELEMENT_NODE: { if ( namespaceURI.size()>0 && prefix.size()==0 ) { return (namespaceURI == theNamespaceURI); } NodePtr attr = attributes.getNamedItem("xmlns"); if ( attr.get() ) { return (attr->getNodeValue() == theNamespaceURI); } NodePtr ancestor = getAncestorElement(this); if ( ancestor.get() ) { return ancestor->isDefaultNamespace(theNamespaceURI); } else { return false; } } case DOCUMENT_NODE: { //just use braces for local declaration DocumentPtr doc = (Document *)this; ElementPtr elem = doc->getDocumentElement(); return elem->isDefaultNamespace(theNamespaceURI); } case ENTITY_NODE: case NOTATION_NODE: case DOCUMENT_TYPE_NODE: case DOCUMENT_FRAGMENT_NODE: return false; case ATTRIBUTE_NODE: {//braces only for scope AttrPtr attr = (Attr *)this; ElementPtr ownerElement = attr->getOwnerElement(); if ( ownerElement.get() ) { return ownerElement->isDefaultNamespace(theNamespaceURI); } else { return false; } } default: { NodePtr ancestor = getAncestorElement(this); if ( ancestor.get() ) { return ancestor->isDefaultNamespace(theNamespaceURI); } else { return false; } } }//switch return false; } /** * */ DOMString NodeImpl::lookupNamespaceURI(const DOMString &thePrefix) { switch (nodeType) { case ELEMENT_NODE: { if ( namespaceURI.size()>0 && prefix == thePrefix ) { DOMString nsURI = namespaceURI; return (nsURI); } if ( hasAttributes() ) { NamedNodeMap attributes = getAttributes(); int nrAttrs = attributes.getLength(); for (int i=0 ; igetPrefix() == "xmlns" && attr->getLocalName() == thePrefix ) { // non default namespace if (attr->getNodeValue().size()>0) { return (attr->getNodeValue()); } return DOMString(""); } else if (attr->getLocalName() == "xmlns" && thePrefix.size()==0) { // default namespace if (attr->getNodeValue().size()>0) { return (attr->getNodeValue()); } return DOMString(""); } } } NodePtr ancestor = getAncestorElement(this); if ( ancestor.get() ) { return ancestor->lookupNamespaceURI(thePrefix); } return DOMString(""); } case DOCUMENT_NODE: { DocumentPtr doc = (Document *)this; ElementPtr elem = doc->getDocumentElement(); return elem->lookupNamespaceURI(thePrefix); } case ENTITY_NODE: case NOTATION_NODE: case DOCUMENT_TYPE_NODE: case DOCUMENT_FRAGMENT_NODE: return DOMString(""); case ATTRIBUTE_NODE: { ElementPtr ownerElement = ((Attr *)this)->getOwnerElement(); if ( ownerElement.get() ) { return ownerElement->lookupNamespaceURI(thePrefix); } else { return DOMString(""); } } default: { NodePtr ancestor = getAncestorElement(this); if ( ancestor.get() ) { return ancestor->lookupNamespaceURI(thePrefix); } else { return DOMString(""); } } }//switch } /** * */ bool NodeImpl::isEqualNode(const NodePtr nodeArg) { if (!nodeArg) return false; if (nodeArg == (NodePtr )this) return true; NodePtr node = nodeArg; if (getNodeType() != node->getNodeType() || getNodeName() != node->getNodeName() || getLocalName() != node->getLocalName() || getNamespaceURI() != node->getNamespaceURI() || getPrefix() != node->getPrefix() || getNodeValue() != node->getNodeValue() || getBaseURI() != node->getBaseURI() ) return false; return true; } /** * */ DOMObject *NodeImpl::getFeature(const DOMString &feature, const DOMString &version) { //dont know return NULL; } /** * */ DOMUserData *NodeImpl::setUserData(const DOMString &key, const DOMUserData *data, const UserDataHandler *handler) { UserDataEntry *entry = userDataEntries; UserDataEntry *prev = NULL; while (entry) { if (entry->key == key) { DOMUserData *oldData = entry->data; entry->data = (DOMUserData *)data; entry->handler = (UserDataHandler *)handler; return oldData; } prev = entry; entry = entry->next; } //Make a new one UserDataEntry *newEntry = new UserDataEntry(key, data, handler); if (!prev) userDataEntries = newEntry; else prev->next = newEntry; return NULL; } /** * */ DOMUserData *NodeImpl::getUserData(const DOMString &key) { UserDataEntry *entry = userDataEntries; while (entry) { if (entry->key == key) return entry->data; entry = entry->next; } return NULL; } //################## //# Non-API methods //################## /** * */ void NodeImpl::setNodeName(const DOMString &qualifiedName) { nodeName = qualifiedName; prefix = ""; localName = ""; for (unsigned int i=0 ; i0 && namespaceURI==theNamespaceURI && prefix.size()>0 && originalElement->lookupNamespaceURI(prefix) == theNamespaceURI) { return (prefix); } if ( hasAttributes() ) { NamedNodeMap attributes = getAttributes(); int nrAttrs = attributes.getLength(); for (int i=0 ; igetLocalName(); if (attr->getPrefix() == "xmlns" && attr->getNodeValue() == theNamespaceURI && originalElement->lookupNamespaceURI(attrLocalName) == theNamespaceURI) { return (attrLocalName); } } } //Get ancestor element, if any NodeImplPtr ancestor = parent; while (ancestor.get() && ancestor->getNodeType()!= Node::ELEMENT_NODE) ancestor = ancestor->parent; if ( ancestor.get() ) { return ancestor->lookupNamespacePrefix(theNamespaceURI, originalElement); } return DOMString(""); } /** * */ NodeImpl::NodeImpl() : Node() { init(); } /** * */ NodeImpl::NodeImpl(const NodeImpl &other) : Node() { init(); assign(other); } /** * */ NodeImpl &NodeImpl::operator=(const NodeImpl &other) { init(); assign(other); return *this; } /** * */ NodeImpl::NodeImpl(DocumentImplPtr owner) : Node() { init(); ownerDocument = owner; } /** * */ NodeImpl::NodeImpl(DocumentImplPtr owner, const DOMString &nodeName) : Node() { init(); ownerDocument = owner; setNodeName(nodeName); } /** * */ NodeImpl::NodeImpl(DocumentImplPtr owner, const DOMString &theNamespaceURI, const DOMString &qualifiedName) : Node() { init(); ownerDocument = owner; //if (owner) // namespaceURI = owner->stringCache(theNamespaceURI); setNodeName(qualifiedName); } /** * */ void NodeImpl::init() { nodeType = 0; //none yet nodeValue = ""; setNodeName(""); namespaceURI = ""; parent = NULL; prev = NULL; next = NULL; userData = NULL; firstChild = NULL; lastChild = NULL; ownerDocument = NULL; userDataEntries = NULL; } /** * */ void NodeImpl::assign(const NodeImpl &other) { ownerDocument = other.ownerDocument; prefix = other.prefix; localName = other.localName; nodeName = other.nodeName; nodeValue = other.nodeValue; namespaceURI = other.namespaceURI; attributes = other.attributes; } /** * */ NodeImpl::~NodeImpl() { if (userDataEntries) delete userDataEntries; //Delete children /** Use smart pointers. do not delete explicitly for (NodePtr n = getFirstChild() ; n.get() ; n=n->getNextSibling() ) delete n; */ firstChild = lastChild = (NodeImpl *)0; } /*######################################################################### ## CharacterDataImpl #########################################################################*/ /** * */ CharacterDataImpl::CharacterDataImpl() : NodeImpl() { } /** * */ CharacterDataImpl::CharacterDataImpl(DocumentImplPtr owner, const DOMString &theValue) : NodeImpl() { ownerDocument = owner; nodeValue = theValue; } /** * */ CharacterDataImpl::~CharacterDataImpl() { } /** * */ DOMString CharacterDataImpl::getData() throw(DOMException) { return nodeValue; } /** * */ void CharacterDataImpl::setData(const DOMString& val) throw(DOMException) { nodeValue = val; } /** * */ unsigned long CharacterDataImpl::getLength() { return nodeValue.size(); } /** * */ DOMString CharacterDataImpl::substringData(unsigned long offset, unsigned long count) throw(DOMException) { return nodeValue.substr(offset, count); } /** * */ void CharacterDataImpl::appendData(const DOMString& arg) throw(DOMException) { nodeValue += arg; } /** * */ void CharacterDataImpl::insertData(unsigned long offset, const DOMString& arg) throw(DOMException) { nodeValue.insert(offset, arg); } /** * */ void CharacterDataImpl::deleteData(unsigned long offset, unsigned long count) throw(DOMException) { nodeValue.erase(offset, count); } /** * */ void CharacterDataImpl::replaceData(unsigned long offset, unsigned long count, const DOMString& arg) throw(DOMException) { nodeValue.replace(offset, count, arg); } /*######################################################################### ## AttrImpl #########################################################################*/ /** * */ DOMString AttrImpl::getName() { return nodeName; } /** * */ bool AttrImpl::getSpecified() { return (nodeValue.size() > 0); } /** * */ DOMString AttrImpl::getValue() { return nodeValue; } /** * */ void AttrImpl::setValue(const DOMString& val) throw(DOMException) { nodeValue = val; } /** * */ ElementPtr AttrImpl::getOwnerElement() { return ownerElement; } /** * */ TypeInfo &AttrImpl::getSchemaTypeInfo() { return typeInfo; } /** * */ bool AttrImpl::getIsId() { return (nodeName == "id"); } //################## //# Non-API methods //################## void AttrImpl::setOwnerElement(const ElementPtr elem) { ownerElement = elem; } /** * */ AttrImpl::AttrImpl(DocumentImplPtr owner, const DOMString &theName) : NodeImpl() { nodeType = ATTRIBUTE_NODE; ownerDocument = owner; setNodeName(theName); } /** * */ AttrImpl::AttrImpl(DocumentImplPtr owner, const DOMString &theNamespaceURI, const DOMString &theQualifiedName) : NodeImpl() { nodeType = ATTRIBUTE_NODE; ownerDocument = owner; //if (owner) // namespaceURI = owner->stringCache(theNamespaceURI); setNodeName(theQualifiedName); } /** * */ AttrImpl::~AttrImpl() { } /*######################################################################### ## ElementImpl #########################################################################*/ /** * */ DOMString ElementImpl::getTagName() { if (prefix.size() > 0) return prefix + ":" + nodeName; else return nodeName; } /** * */ DOMString ElementImpl::getAttribute(const DOMString& name) { NodePtr node = attributes.getNamedItem(name); if (!node || node->getNodeType() != ATTRIBUTE_NODE) return DOMString(""); AttrPtr attr = dynamic_cast(node.get()); return attr->getValue(); } /** * */ void ElementImpl::setAttribute(const DOMString& name, const DOMString& value) throw(DOMException) { AttrImplPtr attr = new AttrImpl(ownerDocument, name); attr->setValue(value); attr->setOwnerElement(this); attributes.setNamedItem(attr); } /** * */ void ElementImpl::removeAttribute(const DOMString& name) throw(DOMException) { attributes.removeNamedItem(name); } /** * */ AttrPtr ElementImpl::getAttributeNode(const DOMString& name) { NodePtr node = attributes.getNamedItem(name); if (!node || node->getNodeType() != ATTRIBUTE_NODE) return NULL; AttrPtr attr = dynamic_cast(node.get()); return attr; } /** * */ AttrPtr ElementImpl::setAttributeNode(AttrPtr attr) throw(DOMException) { attributes.setNamedItem(attr); return attr; } /** * */ AttrPtr ElementImpl::removeAttributeNode(AttrPtr attr) throw(DOMException) { attributes.removeNamedItem(attr->getName()); return attr; } /** * */ void ElementImpl::getElementsByTagNameRecursive(NodeList &list, const DOMString& name, ElementPtr elem) { if (!elem) return; if (name == elem->getTagName()) list.add(elem); for (NodePtr node = elem->getFirstChild() ; node.get() ; node=node->getNextSibling()) { if (node->getNodeType() != Node::ELEMENT_NODE) continue; ElementPtr childElem = dynamic_cast(node.get()); getElementsByTagNameRecursive(list, name, childElem); } } /** * */ NodeList ElementImpl::getElementsByTagName(const DOMString& tagName) { NodeList list; getElementsByTagNameRecursive(list, tagName, this); return list; } /** * */ DOMString ElementImpl::getAttributeNS(const DOMString& namespaceURI, const DOMString& localName) { NodePtr node = attributes.getNamedItemNS(namespaceURI, localName); if (!node || node->getNodeType()!=ATTRIBUTE_NODE) return DOMString(""); AttrPtr attr = dynamic_cast(node.get()); return attr->getValue(); } /** * */ void ElementImpl::setAttributeNS(const DOMString& namespaceURI, const DOMString& qualifiedName, const DOMString& value) throw(DOMException) { AttrImplPtr attr = new AttrImpl(ownerDocument, namespaceURI, qualifiedName); attr->setValue(value); attr->setOwnerElement(this); attributes.setNamedItemNS(attr); } /** * */ void ElementImpl::removeAttributeNS(const DOMString& namespaceURI, const DOMString& localName) throw(DOMException) { attributes.removeNamedItemNS(namespaceURI, localName); } /** * */ AttrPtr ElementImpl::getAttributeNodeNS(const DOMString& namespaceURI, const DOMString& localName) { NodePtr node = attributes.getNamedItemNS(namespaceURI, localName); if (!node || node->getNodeType() != ATTRIBUTE_NODE) return (Attr *)0; AttrPtr attr = dynamic_cast(node.get()); return attr; } /** * */ AttrPtr ElementImpl::setAttributeNodeNS(AttrPtr attr) throw(DOMException) { attributes.setNamedItemNS(attr); return attr; } /** * */ void ElementImpl::getElementsByTagNameNSRecursive(NodeList &list, const DOMString& namespaceURI, const DOMString& tagName, ElementPtr elem) { if (!elem) return; if (namespaceURI == elem->getNamespaceURI() && tagName == elem->getTagName()) list.add(elem); for (NodePtr node = elem->getFirstChild() ; node.get() ; node=node->getNextSibling()) { if (node->getNodeType() != Node::ELEMENT_NODE) continue; ElementPtr childElem = dynamic_cast(node.get()); getElementsByTagNameNSRecursive(list, namespaceURI, tagName, childElem); } } /** * */ NodeList ElementImpl::getElementsByTagNameNS(const DOMString& namespaceURI, const DOMString& localName) { NodeList list; getElementsByTagNameNSRecursive(list, namespaceURI, localName, this); return list; } /** * */ bool ElementImpl::hasAttribute(const DOMString& attrName) { NodePtr node = attributes.getNamedItem(attrName); if (!node || node->getNodeType() != ATTRIBUTE_NODE) return false; return true; } /** * */ bool ElementImpl::hasAttributeNS(const DOMString& namespaceURI, const DOMString& localName) { NodePtr node = attributes.getNamedItemNS(namespaceURI, localName); if (!node || node->getNodeType() != ATTRIBUTE_NODE) return false; return true; } /** * */ TypeInfo &ElementImpl::getSchemaTypeInfo() { return typeInfo; } /** * */ void ElementImpl::setIdAttribute(const DOMString &name, bool isId) throw (DOMException) { //fixme } /** * */ void ElementImpl::setIdAttributeNS(const DOMString &namespaceURI, const DOMString &localName, bool isId) throw (DOMException) { //fixme } /** * */ void ElementImpl::setIdAttributeNode(const AttrPtr idAttr, bool isId) throw (DOMException) { //fixme } //################## //# Non-API methods //################## /** * */ ElementImpl::ElementImpl() : NodeImpl() { nodeType = ELEMENT_NODE; } /** * */ ElementImpl::ElementImpl(DocumentImplPtr owner, const DOMString &tagName) : NodeImpl() { nodeType = ELEMENT_NODE; ownerDocument = owner; setNodeName(tagName); } /** * */ ElementImpl::ElementImpl(DocumentImplPtr owner, const DOMString &theNamespaceURI, const DOMString &qualifiedName) : NodeImpl() { nodeType = ELEMENT_NODE; ownerDocument = owner; setNodeName(qualifiedName); } /** * */ ElementImpl::~ElementImpl() { } /** * */ void ElementImpl::normalizeNamespaces() { //printf("### NORMALIZE\n"); NamedNodeMap attrs = getAttributes(); //####################################### //# Pick up local namespace declarations //####################################### bindingsClear(); //Reset bindings on this node int nrAttrs = attrs.getLength(); for (int i=0; igetNodeType() != Node::ATTRIBUTE_NODE) continue; AttrImplPtr attr = dynamic_cast(attrNode.get()); DOMString attrNS = attr->getNamespaceURI(); DOMString attrName = attr->getLocalName(); DOMString attrPrefix = attr->getPrefix(); DOMString attrValue = attr->getNodeValue(); if (attrName != "xmlns" && attrPrefix != "xmlns") continue; //is the namespace declaration is invalid? if (attrValue == XMLNSNAME || attrName == attrPrefix) { // Note: The prefix xmlns is used only to declare namespace bindings and // is by definition bound to the namespace name http://www.w3.org/2000/xmlns/. // It must not be declared. No other prefix may be bound to this namespace name. //==> Report an error. printf("normalizeNamespaces() error: Namespace %s cannot be reassigned\n", XMLNSNAME); } else { //==> Record the namespace declaration attr->setNamespaceURI(XMLNSNAME); if (attrPrefix.size() > 0) bindingsAdd(attrPrefix, attrValue); else bindingsAdd("*", attrValue);//default } } //####################################### //# Fixup element's namespace //####################################### if ( namespaceURI.size() > 0 ) { DOMString key = prefix; if (key.size() == 0) key = "*"; DOMString binding = bindingsFind(key); //Element's prefix/namespace pair (or default namespace, if no prefix) // are within the scope of a binding if ( binding == namespaceURI ) { //==> do nothing, declaration in scope is inherited // See section "B.1.1: Scope of a binding" for an example } else { /* ==> Create a local namespace declaration attr for this namespace, with Element's current prefix (or a default namespace, if no prefix). If there's a conflicting local declaration already present, change its value to use this namespace. See section "B.1.2: Conflicting namespace declaration" for an example */ DOMString attrName = "xmlns"; if (prefix.size() > 0) { attrName.append(":"); attrName.append(prefix); } setAttribute(attrName, namespaceURI); // NOTE that this may break other nodes within this Element's // subtree, if they're already using this prefix. // They will be repaired when we reach them. } } else // Element has no namespace URI: { //############################################### //# Bob -- alter this from the specs a bit. //# Since the XmlReader does not set namespaces, //# do it here //############################################### DOMString localName = getLocalName(); if ( localName.size()==0 ) { // DOM Level 1 node /* ==> if in process of validation against a namespace aware schema (i.e XML Schema) report a fatal error: the processor can not recover in this situation. Otherwise, report an error: no namespace fixup will be performed on this node. */ printf("normalizeNamespaces() error: no localName\n"); } else { // Element has no pseudo-prefix //there's a conflicting local default namespace declaration already present if ( prefix.size()==0 ) { //==> change its value to use this empty namespace. namespaceURI = bindingsFind("*"); //setAttribute("xmlns", ""); } else //#BOB . I added this. { namespaceURI = bindingsFind(prefix); } // NOTE that this may break other nodes within this Element's // subtree, if they're already using the default namespaces. // They will be repaired when we reach them. } } //####################################### //# Examine and polish the attributes //####################################### nrAttrs = attrs.getLength(); for (int i=0; igetNodeType() != Node::ATTRIBUTE_NODE) continue; AttrPtr attr = dynamic_cast(attrNode.get()); DOMString attrNS = attr->getNamespaceURI(); DOMString attrPrefix = attr->getPrefix(); DOMString attrValue = attr->getNodeValue(); if (attrNS == XMLNSNAME) continue; if ( attrNS.size()>0 ) //Attr[i] has a namespace URI { DOMString attrBinding = bindingsFind(attrPrefix); /* if attribute has no prefix (default namespace decl does not apply to attributes) OR attribute prefix is not declared OR conflict: attribute has a prefix that conflicts with a binding already active in scope */ if ( attrPrefix.size() == 0 || attrBinding.size() == 0) { //namespaceURI matches an in scope declaration of one or more prefixes) DOMString prefixForNS = lookupNamespacePrefix(attrNS, this); if ( prefixForNS.size() > 0 ) { // pick the most local binding available; // if there is more than one pick one arbitrarily //==> change attribute's prefix. attr->setPrefix(prefixForNS); } else { // the current prefix is not null and it has no in scope declaration) if ( attrPrefix.size() > 0 || attrBinding.size() == 0 ) { //==> declare this prefix DOMString newAttrName = "xmlns:"; newAttrName.append(attrPrefix); setAttribute(newAttrName, attrNS); bindingsAdd(attrPrefix, attrNS); } else { // find a prefix following the pattern "NS" +index (starting at 1) // make sure this prefix is not declared in the current scope. // create a local namespace declaration attribute //==> declare this prefix char buf[16]; sprintf(buf, "%d" , ownerDocument->namespaceIndex++); DOMString newPrefix = "NS"; newPrefix.append(buf); DOMString newAttrName = "xmlns:"; newAttrName.append(newPrefix); setAttribute(newAttrName, attrNS); bindingsAdd(newPrefix, attrNS); //==> change attribute's prefix. } } } } else // Attr has no namespace URI { // Attr has no localName if ( attr->getLocalName().size() == 0 ) { // DOM Level 1 node /* ==> if in process of validation against a namespace aware schema (i.e XML Schema) report a fatal error: the processor can not recover in this situation. Otherwise, report an error: no namespace fixup will be performed on this node. */ printf("normalizeNamespaces: no local name for attribute\n"); } else { // attr has no namespace URI and no prefix // no action is required, since attrs don't use default //==> do nothing } } } // end for-all-Attrs //####################################### //# Recursively normalize children //####################################### for (NodePtr child=getFirstChild() ; child.get() ; child=child->getNextSibling()) { if (child->getNodeType() != Node::ELEMENT_NODE) continue; ElementImplPtr childElement = dynamic_cast(child.get()); childElement->normalizeNamespaces(); } } /*######################################################################### ## TextImpl #########################################################################*/ /** * */ TextImpl::TextImpl() : CharacterDataImpl() { nodeType = TEXT_NODE; nodeName = "#text"; } /** * */ TextImpl::TextImpl(DocumentImplPtr owner, const DOMString &value) : CharacterDataImpl() { nodeType = TEXT_NODE; nodeName = "#text"; ownerDocument = owner; nodeValue = value; } /** * */ TextImpl::~TextImpl() { } /** * */ TextPtr TextImpl::splitText(unsigned long offset) throw(DOMException) { return NULL; } /** * */ bool TextImpl::getIsElementContentWhitespace() { return false; } /** * */ DOMString TextImpl::getWholeText() { return nodeValue; } /** * */ TextPtr TextImpl::replaceWholeText(const DOMString &content) throw(DOMException) { return NULL; } /*######################################################################### ## CommentImpl #########################################################################*/ /** * */ CommentImpl::CommentImpl() : CharacterDataImpl() { nodeType = COMMENT_NODE; nodeName = "#comment"; } /** * */ CommentImpl::CommentImpl(DocumentImplPtr owner, const DOMString &value) : CharacterDataImpl() { nodeType = COMMENT_NODE; nodeName = "#comment"; ownerDocument = owner; nodeValue = value; } /** * */ CommentImpl::~CommentImpl() { } /*######################################################################### ## UserDataHandlerImpl #########################################################################*/ /** * */ UserDataHandlerImpl::UserDataHandlerImpl() { } /** * */ UserDataHandlerImpl::~UserDataHandlerImpl() { } /** * */ void UserDataHandlerImpl::handle(unsigned short operation, const DOMString &key, const DOMUserData *data, const NodePtr src, const NodePtr dst) { //do nothing. do we need anything here? } /*######################################################################### ## DOMErrorImpl #########################################################################*/ /** * */ DOMErrorImpl::DOMErrorImpl() { } /** * */ DOMErrorImpl::~DOMErrorImpl() { } /** * */ unsigned short DOMErrorImpl::getSeverity() { return severity; } /** * */ DOMString DOMErrorImpl::getMessage() { return message; } /** * */ DOMString DOMErrorImpl::getType() { return type; } /** * */ DOMObject *DOMErrorImpl::getRelatedException() { return NULL; } /** * */ DOMObject *DOMErrorImpl::getRelatedData() { return NULL; } /** * */ DOMLocator *DOMErrorImpl::getLocation() { //really should fill this in return NULL; } /*######################################################################### ## DOMErrorHandlerImpl #########################################################################*/ /** * */ DOMErrorHandlerImpl::DOMErrorHandlerImpl() { } /** * */ DOMErrorHandlerImpl::~DOMErrorHandlerImpl() { } /** * */ bool DOMErrorHandlerImpl::handleError(const DOMError *error) { if (!error) return false; return true; } /*######################################################################### ## DOMLocatorImpl #########################################################################*/ /** * */ DOMLocatorImpl::DOMLocatorImpl() { } /** * */ DOMLocatorImpl::~DOMLocatorImpl() { } /** * */ long DOMLocatorImpl::getLineNumber() { return lineNumber; } /** * */ long DOMLocatorImpl::getColumnNumber() { return columnNumber; } /** * */ long DOMLocatorImpl::getByteOffset() { return byteOffset; } /** * */ long DOMLocatorImpl::getUtf16Offset() { return utf16Offset; } /** * */ NodePtr DOMLocatorImpl::getRelatedNode() { return relatedNode; } /** * */ DOMString DOMLocatorImpl::getUri() { return uri; } /*######################################################################### ## DOMConfigurationImpl #########################################################################*/ /** * */ DOMConfigurationImpl::DOMConfigurationImpl() { } /** * */ DOMConfigurationImpl::~DOMConfigurationImpl() { } /** * */ void DOMConfigurationImpl::setParameter(const DOMString &name, const DOMUserData *value) throw (DOMException) { } /** * */ DOMUserData *DOMConfigurationImpl::getParameter(const DOMString &name) throw (DOMException) { return NULL; } /** * */ bool DOMConfigurationImpl::canSetParameter(const DOMString &name, const DOMUserData *data) { return false; } /** * */ DOMStringList *DOMConfigurationImpl::getParameterNames() { return NULL; } /*######################################################################### ## CDATASectionImpl #########################################################################*/ /** * */ CDATASectionImpl::CDATASectionImpl() : TextImpl() { nodeType = CDATA_SECTION_NODE; nodeName = "#cdata-section"; } /** * */ CDATASectionImpl::CDATASectionImpl(DocumentImplPtr owner, const DOMString &theValue) : TextImpl() { nodeType = CDATA_SECTION_NODE; nodeName = "#cdata-section"; ownerDocument = owner; nodeValue = theValue; } /** * */ CDATASectionImpl::~CDATASectionImpl() { } /*######################################################################### ## DocumentTypeImpl #########################################################################*/ /** * */ DocumentTypeImpl::DocumentTypeImpl(const DOMString& theName, const DOMString& thePublicId, const DOMString& theSystemId) : NodeImpl() { nodeType = DOCUMENT_TYPE_NODE; nodeName = theName; publicId = thePublicId; systemId = theSystemId; } /** * */ DocumentTypeImpl::~DocumentTypeImpl() { } /** * */ DOMString DocumentTypeImpl::getName() { return nodeName; } /** * */ NamedNodeMap DocumentTypeImpl::getEntities() { return entities; } /** * */ NamedNodeMap DocumentTypeImpl::getNotations() { return notations; } /** * */ DOMString DocumentTypeImpl::getPublicId() { return publicId; } /** * */ DOMString DocumentTypeImpl::getSystemId() { return systemId; } /** * */ DOMString DocumentTypeImpl::getInternalSubset() { return DOMString(""); } /*######################################################################### ## NotationImpl #########################################################################*/ /** * */ NotationImpl::NotationImpl(DocumentImplPtr owner) : NodeImpl() { nodeType = NOTATION_NODE; ownerDocument = owner; } /** * */ NotationImpl::~NotationImpl() { } /** * */ DOMString NotationImpl::getPublicId() { return publicId; } /** * */ DOMString NotationImpl::getSystemId() { return systemId; } /*######################################################################### ## EntityImpl #########################################################################*/ /** * */ EntityImpl::EntityImpl() : NodeImpl() { nodeType = ENTITY_NODE; } /** * */ EntityImpl::EntityImpl(DocumentImplPtr owner) : NodeImpl() { nodeType = ENTITY_NODE; ownerDocument = owner; } /** * */ EntityImpl::~EntityImpl() { } /** * */ DOMString EntityImpl::getPublicId() { return publicId; } /** * */ DOMString EntityImpl::getSystemId() { return systemId; } /** * */ DOMString EntityImpl::getNotationName() { return notationName; } /** * */ DOMString EntityImpl::getInputEncoding() { return inputEncoding; } /** * */ DOMString EntityImpl::getXmlEncoding() { return xmlEncoding; } /** * */ DOMString EntityImpl::getXmlVersion() { return xmlVersion; } /*######################################################################### ## EntityReferenceImpl #########################################################################*/ /** * */ EntityReferenceImpl::EntityReferenceImpl() : NodeImpl() { nodeType = ENTITY_REFERENCE_NODE; } /** * */ EntityReferenceImpl::EntityReferenceImpl(DocumentImplPtr owner, const DOMString &theName) : NodeImpl() { nodeType = ENTITY_REFERENCE_NODE; nodeName = theName; ownerDocument = owner; } /** * */ EntityReferenceImpl::~EntityReferenceImpl() { } /*######################################################################### ## ProcessingInstructionImpl #########################################################################*/ /** * */ ProcessingInstructionImpl::ProcessingInstructionImpl(): NodeImpl() { nodeType = PROCESSING_INSTRUCTION_NODE; } /** * */ ProcessingInstructionImpl::ProcessingInstructionImpl(DocumentImplPtr owner, const DOMString &target, const DOMString &data) : NodeImpl() { nodeType = PROCESSING_INSTRUCTION_NODE; ownerDocument = owner; nodeName = target; nodeValue = data; } /** * */ ProcessingInstructionImpl::~ProcessingInstructionImpl() { } /** * */ DOMString ProcessingInstructionImpl::getTarget() { return nodeName; } /** * */ DOMString ProcessingInstructionImpl::getData() { return nodeValue; } /** * */ void ProcessingInstructionImpl::setData(const DOMString& val) throw(DOMException) { //do something here } /*######################################################################### ## DocumentFragmentImpl #########################################################################*/ /** * */ DocumentFragmentImpl::DocumentFragmentImpl() : NodeImpl() { nodeType = DOCUMENT_FRAGMENT_NODE; nodeName = "#document-fragment"; } /** * */ DocumentFragmentImpl::DocumentFragmentImpl(DocumentImplPtr owner) : NodeImpl() { nodeType = DOCUMENT_FRAGMENT_NODE; nodeName = "#document-fragment"; ownerDocument = owner; } /** * */ DocumentFragmentImpl::~DocumentFragmentImpl() { } /*######################################################################### ## DocumentImpl #########################################################################*/ /** * */ DocumentTypePtr DocumentImpl::getDoctype() { return doctype; } /** * */ DOMImplementation *DocumentImpl::getImplementation() { return parent; } /** * */ ElementPtr DocumentImpl::getDocumentElement() { return documentElement; } /** * */ ElementPtr DocumentImpl::createElement(const DOMString& tagName) throw(DOMException) { ElementPtr elem = new ElementImpl(this, tagName); return elem; } /** * */ DocumentFragmentPtr DocumentImpl::createDocumentFragment() { DocumentFragmentPtr frag = new DocumentFragmentImpl(this); return frag; } /** * */ TextPtr DocumentImpl::createTextNode(const DOMString& data) { TextPtr text = new TextImpl(this, data); return text; } /** * */ CommentPtr DocumentImpl::createComment(const DOMString& data) { CommentPtr comment = new CommentImpl(this, data); return comment; } /** * */ CDATASectionPtr DocumentImpl::createCDATASection(const DOMString& data) throw(DOMException) { CDATASectionPtr cdata = new CDATASectionImpl(this, data); return cdata; } /** * */ ProcessingInstructionPtr DocumentImpl::createProcessingInstruction(const DOMString& target, const DOMString& data) throw(DOMException) { ProcessingInstructionPtr pi = new ProcessingInstructionImpl(this, target, data); return pi; } /** * */ AttrPtr DocumentImpl::createAttribute(const DOMString& attrName) throw(DOMException) { AttrPtr attr = new AttrImpl(this, attrName); return attr; } /** * */ EntityReferencePtr DocumentImpl::createEntityReference(const DOMString& erName) throw(DOMException) { EntityReferencePtr ref = new EntityReferenceImpl(this, erName); return ref; } /** * */ NodeList DocumentImpl::getElementsByTagName(const DOMString& tagname) { NodeList list; ElementImpl::getElementsByTagNameRecursive(list, tagname, documentElement); return list; } /** * */ NodePtr DocumentImpl::importNode(const NodePtr importedNode, bool deep) throw(DOMException) { return NULL; } /** * */ ElementPtr DocumentImpl::createElementNS(const DOMString& namespaceURI, const DOMString& qualifiedName) throw(DOMException) { ElementPtr elem = new ElementImpl(this, namespaceURI, qualifiedName); return elem; } /** * */ AttrPtr DocumentImpl::createAttributeNS(const DOMString& namespaceURI, const DOMString& qualifiedName) throw(DOMException) { AttrPtr attr = new AttrImpl(this, namespaceURI, qualifiedName); return attr; } /** * */ NodeList DocumentImpl::getElementsByTagNameNS(const DOMString& namespaceURI, const DOMString& localName) { NodeList list; ElementImpl::getElementsByTagNameNSRecursive(list, namespaceURI, localName, documentElement); return list; } /** * */ ElementPtr DocumentImpl::getElementById(const DOMString& elementId) { for (NamedElementItem *entry = elementsById.next; entry ; entry=entry->next) if (entry->name == elementId) return entry->elem; return NULL; } /** * */ DOMString DocumentImpl::getInputEncoding() { return inputEncoding; } /** * */ DOMString DocumentImpl::getXmlEncoding() { return xmlEncoding; } /** * */ bool DocumentImpl::getXmlStandalone() { return xmlStandalone; } /** * */ void DocumentImpl::setXmlStandalone(bool val) throw (DOMException) { xmlStandalone = val; } /** * */ DOMString DocumentImpl::getXmlVersion() { return xmlVersion; } /** * */ void DocumentImpl::setXmlVersion(const DOMString &version) throw (DOMException) { xmlVersion = version; } /** * */ bool DocumentImpl::getStrictErrorChecking() { return strictErrorChecking; } /** * */ void DocumentImpl::setStrictErrorChecking(bool val) { strictErrorChecking = val; } /** * */ DOMString DocumentImpl::getDocumentURI() { return documentURI; } /** * */ void DocumentImpl::setDocumentURI(const DOMString &uri) { //documentURI = stringCache(uri); } /** * */ NodePtr DocumentImpl::adoptNode(const NodePtr source) throw (DOMException) { return (NodePtr )source; } /** * */ DOMConfiguration *DocumentImpl::getDomConfig() { return domConfig; } /** * */ void DocumentImpl::normalizeDocument() { //i assume that this means adjusting namespaces & prefixes if (documentElement.get()) documentElement->normalizeNamespaces(); } /** * */ NodePtr DocumentImpl::renameNode(const NodePtr node, const DOMString &namespaceURI, const DOMString &qualifiedName) throw (DOMException) { NodeImplPtr nodeImpl = dynamic_cast (node.get()); nodeImpl->setNodeName(qualifiedName); return node; } //################## //# Non-API methods //################## /** * */ DocumentImpl::DocumentImpl(const DOMImplementation *domImpl, const DOMString &theNamespaceURI, const DOMString &theQualifiedName, const DocumentTypePtr theDoctype) : NodeImpl() { nodeType = DOCUMENT_NODE; nodeName = "#document"; parent = (DOMImplementation *)domImpl; //documentURI = stringCache(theNamespaceURI); qualifiedName = theQualifiedName; if (theDoctype.get()) //only assign if not null. doctype = theDoctype; else doctype = new DocumentTypeImpl("", "", ""); documentElement = new ElementImpl(this, "root"); namespaceIndex = 0; } /** * */ DocumentImpl::~DocumentImpl() { documentElement = NULL; } } //namespace dom } //namespace w3c } //namespace org /*######################################################################### ## E N D O F F I L E #########################################################################*/