GME
13
|
00001 /* 00002 * Licensed to the Apache Software Foundation (ASF) under one or more 00003 * contributor license agreements. See the NOTICE file distributed with 00004 * this work for additional information regarding copyright ownership. 00005 * The ASF licenses this file to You under the Apache License, Version 2.0 00006 * (the "License"); you may not use this file except in compliance with 00007 * the License. You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 /* 00019 * $Id: DOMTextImpl.cpp 678709 2008-07-22 10:56:56Z borisk $ 00020 */ 00021 00022 00023 #include <xercesc/util/XMLUniDefs.hpp> 00024 00025 #include <xercesc/dom/DOMException.hpp> 00026 #include <xercesc/dom/DOMNode.hpp> 00027 #include <xercesc/dom/DOMElement.hpp> 00028 #include <xercesc/dom/DOMCDATASection.hpp> 00029 #include <xercesc/dom/DOMNodeFilter.hpp> 00030 #include <xercesc/dom/DOMTreeWalker.hpp> 00031 00032 #include "DOMDocumentImpl.hpp" 00033 #include "DOMStringPool.hpp" 00034 #include "DOMTextImpl.hpp" 00035 #include "DOMCharacterDataImpl.hpp" 00036 #include "DOMChildNode.hpp" 00037 #include "DOMRangeImpl.hpp" 00038 #include "DOMCasts.hpp" 00039 00040 #include <assert.h> 00041 00042 XERCES_CPP_NAMESPACE_BEGIN 00043 00044 class DOMDocument; 00045 00046 DOMTextImpl::DOMTextImpl(DOMDocument *ownerDoc, const XMLCh *dat) 00047 : fNode(ownerDoc), fCharacterData(ownerDoc, dat) 00048 { 00049 fNode.setIsLeafNode(true); 00050 } 00051 00052 DOMTextImpl:: 00053 DOMTextImpl(DOMDocument *ownerDoc, const XMLCh* dat, XMLSize_t n) 00054 : fNode(ownerDoc), fCharacterData(ownerDoc, dat, n) 00055 { 00056 fNode.setIsLeafNode(true); 00057 } 00058 00059 DOMTextImpl::DOMTextImpl(const DOMTextImpl &other, bool) 00060 : DOMText(other) 00061 , fNode(other.fNode) 00062 , fCharacterData(other.fCharacterData) 00063 { 00064 fNode.setIsLeafNode(true); 00065 } 00066 00067 DOMTextImpl::~DOMTextImpl() 00068 { 00069 } 00070 00071 00072 DOMNode *DOMTextImpl::cloneNode(bool deep) const 00073 { 00074 DOMNode* newNode = new (getOwnerDocument(), DOMMemoryManager::TEXT_OBJECT) DOMTextImpl(*this, deep); 00075 fNode.callUserDataHandlers(DOMUserDataHandler::NODE_CLONED, this, newNode); 00076 return newNode; 00077 } 00078 00079 00080 const XMLCh * DOMTextImpl::getNodeName() const { 00081 static const XMLCh gtext[] = {chPound, chLatin_t, chLatin_e, chLatin_x, chLatin_t, chNull}; 00082 return gtext; 00083 } 00084 00085 DOMNode::NodeType DOMTextImpl::getNodeType() const { 00086 return DOMNode::TEXT_NODE; 00087 } 00088 00089 00090 DOMText *DOMTextImpl::splitText(XMLSize_t offset) 00091 { 00092 if (fNode.isReadOnly()) 00093 { 00094 throw DOMException( 00095 DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); 00096 } 00097 XMLSize_t len = fCharacterData.fDataBuf->getLen(); 00098 if (offset > len) 00099 throw DOMException(DOMException::INDEX_SIZE_ERR, 0, GetDOMNodeMemoryManager); 00100 00101 DOMDocumentImpl *doc = (DOMDocumentImpl *)getOwnerDocument(); 00102 DOMText *newText = doc->createTextNode( 00103 this->substringData(offset, len - offset)); 00104 00105 DOMNode *parent = getParentNode(); 00106 if (parent != 0) 00107 parent->insertBefore(newText, getNextSibling()); 00108 00109 fCharacterData.fDataBuf->chop(offset); 00110 00111 if (doc != 0) { 00112 Ranges* ranges = doc->getRanges(); 00113 if (ranges != 0) { 00114 XMLSize_t sz = ranges->size(); 00115 if (sz != 0) { 00116 for (XMLSize_t i =0; i<sz; i++) { 00117 ranges->elementAt(i)->updateSplitInfo( this, newText, offset); 00118 } 00119 } 00120 } 00121 } 00122 00123 return newText; 00124 } 00125 00126 00127 bool DOMTextImpl::isIgnorableWhitespace() const 00128 { 00129 return fNode.ignorableWhitespace(); 00130 } 00131 00132 00133 00134 void DOMTextImpl::setIgnorableWhitespace(bool ignorable) 00135 { 00136 fNode.ignorableWhitespace(ignorable); 00137 } 00138 00139 00140 bool DOMTextImpl::getIsElementContentWhitespace() const 00141 { 00142 return isIgnorableWhitespace(); 00143 } 00144 00145 const XMLCh* DOMTextImpl::getWholeText() const 00146 { 00147 DOMDocument *doc = getOwnerDocument(); 00148 DOMTreeWalker* pWalker=doc->createTreeWalker(doc->getDocumentElement(), DOMNodeFilter::SHOW_ALL, NULL, true); 00149 pWalker->setCurrentNode((DOMNode*)this); 00150 // Logically-adjacent text nodes are Text or CDATASection nodes that can be visited sequentially in document order or in 00151 // reversed document order without entering, exiting, or passing over Element, Comment, or ProcessingInstruction nodes. 00152 DOMNode* prevNode; 00153 while((prevNode=pWalker->previousNode())!=NULL) 00154 { 00155 if(prevNode->getNodeType()==ELEMENT_NODE || prevNode->getNodeType()==COMMENT_NODE || prevNode->getNodeType()==PROCESSING_INSTRUCTION_NODE) 00156 break; 00157 } 00158 XMLBuffer buff(1023, GetDOMNodeMemoryManager); 00159 DOMNode* nextNode; 00160 while((nextNode=pWalker->nextNode())!=NULL) 00161 { 00162 if(nextNode->getNodeType()==ELEMENT_NODE || nextNode->getNodeType()==COMMENT_NODE || nextNode->getNodeType()==PROCESSING_INSTRUCTION_NODE) 00163 break; 00164 if(nextNode->getNodeType()==TEXT_NODE || nextNode->getNodeType()==CDATA_SECTION_NODE) 00165 buff.append(nextNode->getNodeValue()); 00166 } 00167 pWalker->release(); 00168 00169 XMLCh* wholeString = (XMLCh*) (GetDOMNodeMemoryManager->allocate((buff.getLen()+1)*sizeof(XMLCh))); 00170 XMLString::copyString(wholeString, buff.getRawBuffer()); 00171 return wholeString; 00172 } 00173 00174 DOMText* DOMTextImpl::replaceWholeText(const XMLCh* newText) 00175 { 00176 DOMDocument *doc = getOwnerDocument(); 00177 DOMTreeWalker* pWalker=doc->createTreeWalker(doc->getDocumentElement(), DOMNodeFilter::SHOW_ALL, NULL, true); 00178 pWalker->setCurrentNode((DOMNode*)this); 00179 // Logically-adjacent text nodes are Text or CDATASection nodes that can be visited sequentially in document order or in 00180 // reversed document order without entering, exiting, or passing over Element, Comment, or ProcessingInstruction nodes. 00181 DOMNode* pFirstTextNode=this; 00182 DOMNode* prevNode; 00183 while((prevNode=pWalker->previousNode())!=NULL) 00184 { 00185 if(prevNode->getNodeType()==ELEMENT_NODE || prevNode->getNodeType()==COMMENT_NODE || prevNode->getNodeType()==PROCESSING_INSTRUCTION_NODE) 00186 break; 00187 pFirstTextNode=prevNode; 00188 } 00189 // before doing any change we need to check if we are going to remove an entity reference that doesn't contain just text 00190 DOMNode* pCurrentNode=pWalker->getCurrentNode(); 00191 DOMNode* nextNode; 00192 while((nextNode=pWalker->nextNode())!=NULL) 00193 { 00194 if(nextNode->getNodeType()==ELEMENT_NODE || nextNode->getNodeType()==COMMENT_NODE || nextNode->getNodeType()==PROCESSING_INSTRUCTION_NODE) 00195 break; 00196 if(nextNode->getNodeType()==ENTITY_REFERENCE_NODE) 00197 { 00198 DOMTreeWalker* pInnerWalker=doc->createTreeWalker(nextNode, DOMNodeFilter::SHOW_ALL, NULL, true); 00199 while(pInnerWalker->nextNode()) 00200 { 00201 short nodeType=pInnerWalker->getCurrentNode()->getNodeType(); 00202 if(nodeType!=ENTITY_REFERENCE_NODE && nodeType!=TEXT_NODE && nodeType!=CDATA_SECTION_NODE) 00203 throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, GetDOMNodeMemoryManager); 00204 } 00205 pInnerWalker->release(); 00206 } 00207 } 00208 DOMText* retVal=NULL; 00209 // if the first node in the chain is a text node, replace its content, otherwise create a new node 00210 if(newText && *newText) 00211 { 00212 if(!castToNodeImpl(pFirstTextNode)->isReadOnly() && (pFirstTextNode->getNodeType()==TEXT_NODE || pFirstTextNode->getNodeType()==CDATA_SECTION_NODE)) 00213 { 00214 pFirstTextNode->setNodeValue(newText); 00215 retVal=(DOMText*)pFirstTextNode; 00216 } 00217 else 00218 { 00219 if(getNodeType()==TEXT_NODE) 00220 retVal=doc->createTextNode(newText); 00221 else 00222 retVal=doc->createCDATASection(newText); 00223 pFirstTextNode->getParentNode()->insertBefore(retVal, pFirstTextNode); 00224 } 00225 } 00226 // now delete all the following text nodes 00227 pWalker->setCurrentNode(pCurrentNode); 00228 while((nextNode=pWalker->nextNode())!=NULL) 00229 { 00230 if(nextNode->getNodeType()==ELEMENT_NODE || nextNode->getNodeType()==COMMENT_NODE || nextNode->getNodeType()==PROCESSING_INSTRUCTION_NODE) 00231 break; 00232 if(nextNode!=retVal) 00233 { 00234 // keep the tree walker valid 00235 pWalker->previousNode(); 00236 nextNode->getParentNode()->removeChild(nextNode); 00237 nextNode->release(); 00238 } 00239 } 00240 pWalker->release(); 00241 return retVal; 00242 } 00243 00244 00245 void DOMTextImpl::release() 00246 { 00247 if (fNode.isOwned() && !fNode.isToBeReleased()) 00248 throw DOMException(DOMException::INVALID_ACCESS_ERR,0, GetDOMNodeMemoryManager); 00249 00250 DOMDocumentImpl* doc = (DOMDocumentImpl*) getOwnerDocument(); 00251 if (doc) { 00252 fNode.callUserDataHandlers(DOMUserDataHandler::NODE_DELETED, 0, 0); 00253 fCharacterData.releaseBuffer(); 00254 doc->release(this, DOMMemoryManager::TEXT_OBJECT); 00255 } 00256 else { 00257 // shouldn't reach here 00258 throw DOMException(DOMException::INVALID_ACCESS_ERR,0, GetDOMNodeMemoryManager); 00259 } 00260 } 00261 00262 // 00263 // Delegation functions 00264 // 00265 DOMNode* DOMTextImpl::appendChild(DOMNode *newChild) {return fNode.appendChild (newChild); } 00266 DOMNamedNodeMap* DOMTextImpl::getAttributes() const {return fNode.getAttributes (); } 00267 DOMNodeList* DOMTextImpl::getChildNodes() const {return fNode.getChildNodes (); } 00268 DOMNode* DOMTextImpl::getFirstChild() const {return fNode.getFirstChild (); } 00269 DOMNode* DOMTextImpl::getLastChild() const {return fNode.getLastChild (); } 00270 const XMLCh* DOMTextImpl::getLocalName() const {return fNode.getLocalName (); } 00271 const XMLCh* DOMTextImpl::getNamespaceURI() const {return fNode.getNamespaceURI (); } 00272 DOMNode* DOMTextImpl::getNextSibling() const {return fChild.getNextSibling (); } 00273 const XMLCh* DOMTextImpl::getNodeValue() const {return fCharacterData.getNodeValue (); } 00274 DOMDocument* DOMTextImpl::getOwnerDocument() const {return fNode.getOwnerDocument (); } 00275 const XMLCh* DOMTextImpl::getPrefix() const {return fNode.getPrefix (); } 00276 DOMNode* DOMTextImpl::getParentNode() const {return fChild.getParentNode (this); } 00277 DOMNode* DOMTextImpl::getPreviousSibling() const {return fChild.getPreviousSibling (this); } 00278 bool DOMTextImpl::hasChildNodes() const {return fNode.hasChildNodes (); } 00279 DOMNode* DOMTextImpl::insertBefore(DOMNode *newChild, DOMNode *refChild) 00280 {return fNode.insertBefore (newChild, refChild); } 00281 void DOMTextImpl::normalize() {fNode.normalize (); } 00282 DOMNode* DOMTextImpl::removeChild(DOMNode *oldChild) {return fNode.removeChild (oldChild); } 00283 DOMNode* DOMTextImpl::replaceChild(DOMNode *newChild, DOMNode *oldChild) 00284 {return fNode.replaceChild (newChild, oldChild); } 00285 bool DOMTextImpl::isSupported(const XMLCh *feature, const XMLCh *version) const 00286 {return fNode.isSupported (feature, version); } 00287 void DOMTextImpl::setPrefix(const XMLCh *prefix) {fNode.setPrefix(prefix); } 00288 bool DOMTextImpl::hasAttributes() const {return fNode.hasAttributes(); } 00289 bool DOMTextImpl::isSameNode(const DOMNode* other) const {return fNode.isSameNode(other); } 00290 bool DOMTextImpl::isEqualNode(const DOMNode* arg) const {return fNode.isEqualNode(arg); } 00291 void* DOMTextImpl::setUserData(const XMLCh* key, void* data, DOMUserDataHandler* handler) 00292 {return fNode.setUserData(key, data, handler); } 00293 void* DOMTextImpl::getUserData(const XMLCh* key) const {return fNode.getUserData(key); } 00294 const XMLCh* DOMTextImpl::getBaseURI() const {return fNode.getBaseURI(); } 00295 short DOMTextImpl::compareDocumentPosition(const DOMNode* other) const {return fNode.compareDocumentPosition(other); } 00296 const XMLCh* DOMTextImpl::getTextContent() const {return fNode.getTextContent(); } 00297 void DOMTextImpl::setTextContent(const XMLCh* textContent){fNode.setTextContent(textContent); } 00298 const XMLCh* DOMTextImpl::lookupPrefix(const XMLCh* namespaceURI) const {return fNode.lookupPrefix(namespaceURI); } 00299 bool DOMTextImpl::isDefaultNamespace(const XMLCh* namespaceURI) const {return fNode.isDefaultNamespace(namespaceURI); } 00300 const XMLCh* DOMTextImpl::lookupNamespaceURI(const XMLCh* prefix) const {return fNode.lookupNamespaceURI(prefix); } 00301 void* DOMTextImpl::getFeature(const XMLCh* feature, const XMLCh* version) const {return fNode.getFeature(feature, version); } 00302 00303 00304 00305 // 00306 // Delegation of CharacerData functions. 00307 // 00308 00309 00310 const XMLCh* DOMTextImpl::getData() const {return fCharacterData.getData();} 00311 XMLSize_t DOMTextImpl::getLength() const {return fCharacterData.getLength();} 00312 const XMLCh* DOMTextImpl::substringData(XMLSize_t offset, XMLSize_t count) const 00313 {return fCharacterData.substringData(this, offset, count);} 00314 void DOMTextImpl::appendData(const XMLCh *arg) {fCharacterData.appendData(this, arg);} 00315 void DOMTextImpl::insertData(XMLSize_t offset, const XMLCh *arg) 00316 {fCharacterData.insertData(this, offset, arg);} 00317 void DOMTextImpl::deleteData(XMLSize_t offset, XMLSize_t count) 00318 {fCharacterData.deleteData(this, offset, count);} 00319 void DOMTextImpl::replaceData(XMLSize_t offset, XMLSize_t count, const XMLCh *arg) 00320 {fCharacterData.replaceData(this, offset, count, arg);} 00321 void DOMTextImpl::setData(const XMLCh *data) {fCharacterData.setData(this, data);} 00322 void DOMTextImpl::setNodeValue(const XMLCh *nodeValue) {fCharacterData.setNodeValue (this, nodeValue); } 00323 00324 void DOMTextImpl::appendData(const XMLCh *arg, XMLSize_t n) {fCharacterData.appendData(this, arg, n);} 00325 00326 XERCES_CPP_NAMESPACE_END