Back to index

lightning-sunbird  0.9+nobinonly
NodeDefinition.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (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  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * The MITRE Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 // Tom Kneeland (3/29/99)
00039 //
00040 //  Implementation of the Document Object Model Level 1 Core
00041 //    Implementation of the NodeDefinition Class
00042 //
00043 // Modification History:
00044 // Who  When      What
00045 // TK   03/29/99  Created
00046 //
00047 
00048 #include "dom.h"
00049 #include "nsVoidArray.h"
00050 #include "txURIUtils.h"
00051 #include "txAtoms.h"
00052 #include <string.h>
00053 
00054 NodeDefinition::NodeDefinition(NodeType type, const nsAString& name,
00055                                const nsAString& value, Document* owner)
00056 {
00057   nodeName = name;
00058   Init(type, value, owner);
00059 }
00060 
00061 NodeDefinition::NodeDefinition(NodeType aType, const nsAString& aValue,
00062                                Document* aOwner)
00063 {
00064   switch (aType)
00065   {
00066     case CDATA_SECTION_NODE:
00067     {
00068       nodeName.AssignLiteral("#cdata-section");
00069       break;
00070     }
00071     case COMMENT_NODE:
00072     {
00073       nodeName.AssignLiteral("#comment");
00074       break;
00075     }
00076     case DOCUMENT_NODE:
00077     {
00078       nodeName.AssignLiteral("#document");
00079       break;
00080     }
00081     case DOCUMENT_FRAGMENT_NODE:
00082     {
00083       nodeName.AssignLiteral("#document-fragment");
00084       break;
00085     }
00086     case TEXT_NODE:
00087     {
00088       nodeName.AssignLiteral("#text");
00089       break;
00090     }
00091     default:
00092     {
00093       break;
00094     }
00095   }
00096   Init(aType, aValue, aOwner);
00097 }
00098 
00099 //
00100 // This node is being destroyed, so loop through and destroy all the children.
00101 //
00102 NodeDefinition::~NodeDefinition()
00103 {
00104   DeleteChildren();
00105   delete mOrderInfo;
00106 }
00107 
00108 void
00109 NodeDefinition::Init(NodeType aType, const nsAString& aValue,
00110                      Document* aOwner)
00111 {
00112   nodeType = aType;
00113   nodeValue = aValue;
00114   ownerDocument = aOwner;
00115 
00116   parentNode = nsnull;
00117   previousSibling = nsnull;
00118   nextSibling = nsnull;;
00119   firstChild = nsnull;
00120   lastChild = nsnull;
00121 
00122   length = 0;
00123 
00124   mOrderInfo = 0;
00125 }
00126 
00127 //
00128 //Remove and delete all children of this node
00129 //
00130 void NodeDefinition::DeleteChildren()
00131 {
00132   NodeDefinition* pCurrent = firstChild;
00133   NodeDefinition* pDestroyer;
00134 
00135   while (pCurrent)
00136     {
00137       pDestroyer = pCurrent;
00138       pCurrent = pCurrent->nextSibling;
00139       delete pDestroyer;
00140     }
00141 
00142   length = 0;
00143   firstChild = nsnull;
00144   lastChild = nsnull;
00145 }
00146 
00147 nsresult NodeDefinition::getNodeName(nsAString& aName) const
00148 {
00149   aName = nodeName;
00150   return NS_OK;
00151 }
00152 
00153 nsresult NodeDefinition::getNodeValue(nsAString& aValue)
00154 {
00155   aValue = nodeValue;
00156   return NS_OK;
00157 }
00158 
00159 unsigned short NodeDefinition::getNodeType() const
00160 {
00161   return nodeType;
00162 }
00163 
00164 Node* NodeDefinition::getParentNode() const
00165 {
00166   return parentNode;
00167 }
00168 
00169 Node* NodeDefinition::getFirstChild() const
00170 {
00171   return firstChild;
00172 }
00173 
00174 Node* NodeDefinition::getLastChild() const
00175 {
00176   return lastChild;
00177 }
00178 
00179 Node* NodeDefinition::getPreviousSibling() const
00180 {
00181   return previousSibling;
00182 }
00183 
00184 Node* NodeDefinition::getNextSibling() const
00185 {
00186   return nextSibling;
00187 }
00188 
00189 NamedNodeMap* NodeDefinition::getAttributes()
00190 {
00191   return 0;
00192 }
00193 
00194 Document* NodeDefinition::getOwnerDocument() const
00195 {
00196   return ownerDocument;
00197 }
00198 
00199 Node* NodeDefinition::item(PRUint32 index)
00200 {
00201   PRUint32 selectLoop;
00202   NodeDefinition* pSelectNode = firstChild;
00203 
00204   if (index < length)
00205     {
00206       for (selectLoop=0;selectLoop<index;selectLoop++)
00207         pSelectNode = pSelectNode->nextSibling;
00208 
00209       return pSelectNode;
00210     }
00211 
00212   return nsnull;
00213 }
00214 
00215 PRUint32 NodeDefinition::getLength()
00216 {
00217   return length;
00218 }
00219 
00220 void NodeDefinition::setNodeValue(const nsAString& newNodeValue)
00221 {
00222   nodeValue = newNodeValue;
00223 }
00224 
00225 Node* NodeDefinition::appendChild(Node* newChild)
00226 {
00227   return nsnull;
00228 }
00229 
00230 NodeDefinition* NodeDefinition::implAppendChild(NodeDefinition* newChild)
00231 {
00232   // The new child should not be a child of any other node
00233   if (!newChild->previousSibling && !newChild->nextSibling &&
00234       !newChild->parentNode)
00235     {
00236       newChild->previousSibling = lastChild;
00237 
00238       if (lastChild)
00239         lastChild->nextSibling = newChild;
00240 
00241       lastChild = newChild;
00242 
00243       newChild->parentNode = this;
00244 
00245       if (!newChild->previousSibling)
00246         firstChild = newChild;
00247 
00248       ++length;
00249 
00250       return newChild;
00251     }
00252 
00253   return nsnull;
00254 }
00255 
00256 NodeDefinition* NodeDefinition::implRemoveChild(NodeDefinition* oldChild)
00257 {
00258   if (oldChild != firstChild)
00259     oldChild->previousSibling->nextSibling = oldChild->nextSibling;
00260   else
00261     firstChild = oldChild->nextSibling;
00262 
00263   if (oldChild != lastChild)
00264     oldChild->nextSibling->previousSibling = oldChild->previousSibling;
00265   else
00266     lastChild = oldChild->previousSibling;
00267 
00268   oldChild->nextSibling = nsnull;
00269   oldChild->previousSibling = nsnull;
00270   oldChild->parentNode = nsnull;
00271 
00272   --length;
00273 
00274   return oldChild;
00275 }
00276 
00277 MBool NodeDefinition::hasChildNodes() const
00278 {
00279   if (firstChild)
00280     return MB_TRUE;
00281   else
00282     return MB_FALSE;
00283 }
00284 
00285 MBool NodeDefinition::getLocalName(nsIAtom** aLocalName)
00286 {
00287   if (!aLocalName)
00288     return MB_FALSE;
00289   *aLocalName = 0;
00290   return MB_TRUE;
00291 }
00292 
00293 nsresult NodeDefinition::getNamespaceURI(nsAString& aNSURI)
00294 {
00295   return txStandaloneNamespaceManager::getNamespaceURI(getNamespaceID(),
00296                                                        aNSURI);
00297 }
00298 
00299 PRInt32 NodeDefinition::getNamespaceID()
00300 {
00301   return kNameSpaceID_None;
00302 }
00303 
00304 //
00305 // Looks up the Namespace associated with a certain prefix in the context of
00306 // this node.
00307 //
00308 // @return namespace associated with prefix
00309 //
00310 PRInt32 NodeDefinition::lookupNamespaceID(nsIAtom* aPrefix)
00311 {
00312   // this is http://www.w3.org/2000/xmlns/,
00313   // ID = kNameSpaceID_XMLNS, see txStandaloneNamespaceManager::Init
00314   if (aPrefix == txXMLAtoms::xmlns)
00315     return kNameSpaceID_XMLNS; 
00316   // this is http://www.w3.org/XML/1998/namespace,
00317   // ID = kNameSpaceID_XML, see txStandaloneNamespaceManager::Init
00318   if (aPrefix == txXMLAtoms::xml)
00319     return kNameSpaceID_XML; 
00320 
00321   Node* node = this;
00322   if (node->getNodeType() != Node::ELEMENT_NODE)
00323     node = node->getXPathParent();
00324 
00325   nsAutoString name(NS_LITERAL_STRING("xmlns:"));
00326   if (aPrefix && (aPrefix != txXMLAtoms::_empty)) {
00327       //  We have a prefix, search for xmlns:prefix attributes.
00328       nsAutoString prefixString;
00329       aPrefix->ToString(prefixString);
00330       name.Append(prefixString);
00331   }
00332   else {
00333       // No prefix, look up the default namespace by searching for xmlns
00334       // attributes. Remove the trailing :, set length to 5 (xmlns).
00335       name.Truncate(5);
00336   }
00337   Attr* xmlns;
00338   while (node && node->getNodeType() == Node::ELEMENT_NODE) {
00339     if ((xmlns = ((Element*)node)->getAttributeNode(name))) {
00340       /*
00341        * xmlns:foo = "" makes "" a valid URI, so get that.
00342        * xmlns = "" resolves to 0 (null Namespace) (caught above)
00343        * in Element::getNamespaceID()
00344        */
00345       nsAutoString nsURI;
00346       xmlns->getNodeValue(nsURI);
00347       return txStandaloneNamespaceManager::getNamespaceID(nsURI);
00348     }
00349     node = node->getXPathParent();
00350   }
00351   if (!aPrefix || (aPrefix == txXMLAtoms::_empty))
00352       return kNameSpaceID_None;
00353   return kNameSpaceID_Unknown;
00354 }
00355 
00356 Node* NodeDefinition::getXPathParent()
00357 {
00358   return parentNode;
00359 }
00360 
00361 //
00362 // Returns the base URI of the node. Acccounts for xml:base
00363 // attributes.
00364 //
00365 // @return base URI for the node
00366 //
00367 nsresult NodeDefinition::getBaseURI(nsAString& aURI)
00368 {
00369   Node* node = this;
00370   nsStringArray baseUrls;
00371   nsAutoString url;
00372 
00373   while (node) {
00374     switch (node->getNodeType()) {
00375       case Node::ELEMENT_NODE :
00376         if (((Element*)node)->getAttr(txXMLAtoms::base, kNameSpaceID_XML,
00377                                       url))
00378           baseUrls.AppendString(url);
00379         break;
00380 
00381       case Node::DOCUMENT_NODE :
00382         node->getBaseURI(url);
00383         baseUrls.AppendString(url);
00384         break;
00385     
00386       default:
00387         break;
00388     }
00389     node = node->getXPathParent();
00390   }
00391 
00392   PRInt32 count = baseUrls.Count();
00393   if (count) {
00394     baseUrls.StringAt(--count, aURI);
00395 
00396     while (count > 0) {
00397       nsAutoString dest;
00398       URIUtils::resolveHref(*baseUrls[--count], aURI, dest);
00399       aURI = dest;
00400     }
00401   }
00402   
00403   return NS_OK;
00404 } // getBaseURI
00405 
00406 /*
00407  * Compares document position of this node relative to another node
00408  */
00409 PRInt32 NodeDefinition::compareDocumentPosition(Node* aOther)
00410 {
00411   OrderInfo* myOrder = getOrderInfo();
00412   OrderInfo* otherOrder = ((NodeDefinition*)aOther)->getOrderInfo();
00413   if (!myOrder || !otherOrder)
00414       return -1;
00415 
00416   if (myOrder->mRoot == otherOrder->mRoot) {
00417     int c = 0;
00418     while (c < myOrder->mSize && c < otherOrder->mSize) {
00419       if (myOrder->mOrder[c] < otherOrder->mOrder[c])
00420         return -1;
00421       if (myOrder->mOrder[c] > otherOrder->mOrder[c])
00422         return 1;
00423       ++c;
00424     }
00425     if (c < myOrder->mSize)
00426       return 1;
00427     if (c < otherOrder->mSize)
00428       return -1;
00429     return 0;
00430   }
00431 
00432   if (myOrder->mRoot < otherOrder->mRoot)
00433     return -1;
00434 
00435   return 1;
00436 }
00437 
00438 /*
00439  * Get order information for node
00440  */
00441 NodeDefinition::OrderInfo* NodeDefinition::getOrderInfo()
00442 {
00443   if (mOrderInfo)
00444     return mOrderInfo;
00445 
00446   mOrderInfo = new OrderInfo;
00447   if (!mOrderInfo)
00448     return 0;
00449 
00450   Node* parent = getXPathParent();
00451   if (!parent) {
00452     mOrderInfo->mOrder = 0;
00453     mOrderInfo->mSize = 0;
00454     mOrderInfo->mRoot = this;
00455     return mOrderInfo;
00456   }
00457 
00458   OrderInfo* parentOrder = ((NodeDefinition*)parent)->getOrderInfo();
00459   mOrderInfo->mSize = parentOrder->mSize + 1;
00460   mOrderInfo->mRoot = parentOrder->mRoot;
00461   mOrderInfo->mOrder = new PRUint32[mOrderInfo->mSize];
00462   if (!mOrderInfo->mOrder) {
00463     delete mOrderInfo;
00464     mOrderInfo = 0;
00465     return 0;
00466   }
00467   memcpy(mOrderInfo->mOrder,
00468          parentOrder->mOrder,
00469          parentOrder->mSize * sizeof(PRUint32*));
00470 
00471   // Get childnumber of this node
00472   int lastElem = parentOrder->mSize;
00473   switch (getNodeType()) {
00474     case Node::ATTRIBUTE_NODE:
00475     {
00476       NS_ASSERTION(parent->getNodeType() == Node::ELEMENT_NODE,
00477                    "parent to attribute is not an element");
00478 
00479       Element* elem = (Element*)parent;
00480       PRUint32 i;
00481       NamedNodeMap* attrs = elem->getAttributes();
00482       for (i = 0; i < attrs->getLength(); ++i) {
00483         if (attrs->item(i) == this) {
00484           mOrderInfo->mOrder[lastElem] = i + kTxAttrIndexOffset;
00485           return mOrderInfo;
00486         }
00487       }
00488       break;
00489     }
00490     // XXX Namespace: need to take care of namespace nodes here
00491     default:
00492     {
00493       PRUint32 i = 0;
00494       Node * child = parent->getFirstChild();
00495       while (child) {
00496         if (child == this) {
00497           mOrderInfo->mOrder[lastElem] = i + kTxChildIndexOffset;
00498           return mOrderInfo;
00499         }
00500         ++i;
00501         child = child->getNextSibling();
00502       }
00503       break;
00504     }
00505   }
00506 
00507   NS_ASSERTION(0, "unable to get childnumber");
00508   mOrderInfo->mOrder[lastElem] = 0;
00509   return mOrderInfo;
00510 }
00511 
00512 /*
00513  * OrderInfo destructor
00514  */
00515 NodeDefinition::OrderInfo::~OrderInfo()
00516 {
00517     delete [] mOrder;
00518 }