Back to index

lightning-sunbird  0.9+nobinonly
dom.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 //
00042 // Modification History:
00043 // Who  When        What
00044 // TK   03/29/99    Created
00045 // LF   08/06/1999  Changed static const short NodeType to enum
00046 //                  Added "friend NamedNodeMap"; to NodeListDefinition
00047 //
00048 
00049 #ifndef MITRE_DOM
00050 #define MITRE_DOM
00051 
00052 #ifdef __BORLANDC__
00053 #include <stdlib.h>
00054 #endif
00055 
00056 #include "List.h"
00057 #include "nsIAtom.h"
00058 #include "nsDoubleHashtable.h"
00059 #include "nsString.h"
00060 #include "nsVoidArray.h"
00061 #include "txCore.h"
00062 
00063 #define kTxNsNodeIndexOffset 0x00000000;
00064 #define kTxAttrIndexOffset 0x40000000;
00065 #define kTxChildIndexOffset 0x80000000;
00066 
00067 class NamedNodeMap;
00068 class Document;
00069 class Element;
00070 class Attr;
00071 class ProcessingInstruction;
00072 
00073 #define kNameSpaceID_Unknown -1
00074 #define kNameSpaceID_None     0
00075 // not really a namespace, but it needs to play the game
00076 #define kNameSpaceID_XMLNS    1 
00077 #define kNameSpaceID_XML      2
00078 // kNameSpaceID_XSLT is 6 for module, see nsINameSpaceManager.h
00079 #define kNameSpaceID_XSLT     3
00080 
00081 //
00082 // Abstract Class defining the interface for a Node.  See NodeDefinition below
00083 // for the actual implementation of the WC3 node.
00084 //
00085 class Node : public TxObject
00086 {
00087   public:
00088     //Node type constants
00089     //-- LF - changed to enum
00090     enum NodeType {
00091         ELEMENT_NODE = 1,
00092         ATTRIBUTE_NODE,
00093         TEXT_NODE,
00094         CDATA_SECTION_NODE,
00095         ENTITY_REFERENCE_NODE,
00096         ENTITY_NODE,
00097         PROCESSING_INSTRUCTION_NODE,
00098         COMMENT_NODE,
00099         DOCUMENT_NODE,
00100         DOCUMENT_TYPE_NODE,
00101         DOCUMENT_FRAGMENT_NODE,
00102         NOTATION_NODE
00103     };
00104 
00105     virtual ~Node() {}
00106 
00107     //Read functions
00108     virtual nsresult getNodeName(nsAString& aName) const = 0;
00109     virtual nsresult getNodeValue(nsAString& aValue) = 0;
00110     virtual unsigned short getNodeType() const = 0;
00111     virtual Node* getParentNode() const = 0;
00112     virtual Node* getFirstChild() const = 0;
00113     virtual Node* getLastChild() const = 0;
00114     virtual Node* getPreviousSibling() const = 0;
00115     virtual Node* getNextSibling() const = 0;
00116     virtual NamedNodeMap* getAttributes() = 0;
00117     virtual Document* getOwnerDocument() const = 0;
00118 
00119     //Write functions
00120     virtual void setNodeValue(const nsAString& nodeValue) = 0;
00121 
00122     //Node manipulation functions
00123     virtual Node* appendChild(Node* newChild) = 0;
00124 
00125     virtual MBool hasChildNodes() const = 0;
00126     
00127     //From DOM3 26-Jan-2001 WD
00128     virtual nsresult getBaseURI(nsAString& aURI) = 0;
00129 
00130     //Introduced in DOM2
00131     virtual nsresult getNamespaceURI(nsAString& aNSURI) = 0;
00132 
00133     //txXPathNode functions
00134     virtual MBool getLocalName(nsIAtom** aLocalName) = 0;
00135     virtual PRInt32 getNamespaceID() = 0;
00136     virtual PRInt32 lookupNamespaceID(nsIAtom* aPrefix) = 0;
00137     virtual Node* getXPathParent() = 0;
00138     virtual PRInt32 compareDocumentPosition(Node* aOther) = 0;
00139 };
00140 
00141 //
00142 // Abstract class containing the Interface for a NodeList.  See NodeDefinition
00143 // below for the actual implementation of a WC3 NodeList as it applies to the
00144 // getChildNodes Node function.  Also see NodeListDefinition for the
00145 // implementation of a NodeList as it applies to such functions as
00146 // getElementByTagName.
00147 //
00148 class NodeList
00149 {
00150   public:
00151     virtual Node* item(PRUint32 index) = 0;
00152     virtual PRUint32 getLength() = 0;
00153   protected:
00154     PRUint32 length;
00155 };
00156 
00157 //
00158 //Definition of the implementation of a NodeList.  This class maintains a
00159 //linked list of pointers to Nodes.  "Friends" of the class can add and remove
00160 //pointers to Nodes as needed.
00161 //      *** NOTE: Is there any need for someone to "remove" a node from the
00162 //                list?
00163 //
00164 class NodeListDefinition : public NodeList
00165 {
00166   friend class NamedNodeMap; //-- LF
00167   friend class txXPathTreeWalker;
00168   public:
00169     NodeListDefinition();
00170     virtual ~NodeListDefinition();
00171 
00172     void append(Node& newNode);
00173     void append(Node* newNode);
00174 
00175     //Inherited from NodeList
00176     Node* item(PRUint32 index);
00177     PRUint32 getLength();
00178 
00179   protected:
00180     struct ListItem {
00181       ListItem* next;
00182       ListItem* prev;
00183       Node* node;
00184     };
00185 
00186     ListItem* firstItem;
00187     ListItem* lastItem;
00188 };
00189 
00190 //
00191 //Definition of a NamedNodeMap.  For the time being it builds off the
00192 //NodeListDefinition class.  This will probably change when NamedNodeMap needs
00193 //to move to a more efficient search algorithm for attributes.
00194 //
00195 class NamedNodeMap : public NodeListDefinition
00196 {
00197   public:
00198     NamedNodeMap();
00199     virtual ~NamedNodeMap();
00200 
00201     Node* getNamedItem(const nsAString& name);
00202     virtual Node* setNamedItem(Node* arg);
00203     virtual Node* removeNamedItem(const nsAString& name);
00204 
00205   private:
00206     NodeListDefinition::ListItem* findListItemByName(const nsAString& name);
00207     // txXPathTreeWalker is friend to speed up attr iterations
00208     friend class txXPathTreeWalker;
00209 };
00210 
00211 //
00212 // Subclass of NamedNodeMap that contains a list of attributes.
00213 // Whenever an attribute is added to or removed from the map, the attributes
00214 // ownerElement is updated.
00215 //
00216 class AttrMap : public NamedNodeMap
00217 {
00218     // Elenent needs to be friend to be able to set the AttrMaps ownerElement
00219     friend class Element;
00220 
00221   public:
00222     AttrMap();
00223     virtual ~AttrMap();
00224 
00225     Node* setNamedItem(Node* arg);
00226     Node* removeNamedItem(const nsAString& name);
00227     void clear();
00228 
00229   private:
00230     Element* ownerElement;
00231 };
00232 
00233 //
00234 // Definition and Implementation of Node and NodeList functionality.  This is
00235 // the central class, from which all other DOM classes (objects) are derrived.
00236 // Users of this DOM should work strictly with the Node interface and NodeList
00237 // interface (see above for those definitions)
00238 //
00239 class NodeDefinition : public Node, public NodeList
00240 {
00241   public:
00242     virtual ~NodeDefinition();      //Destructor, delete all children of node
00243 
00244     //Read functions
00245     nsresult getNodeName(nsAString& aName) const;
00246     nsresult getNodeValue(nsAString& aValue);
00247     unsigned short getNodeType() const;
00248     Node* getParentNode() const;
00249     Node* getFirstChild() const;
00250     Node* getLastChild() const;
00251     Node* getPreviousSibling() const;
00252     Node* getNextSibling() const;
00253     virtual NamedNodeMap* getAttributes();
00254     Document* getOwnerDocument() const;
00255 
00256     //Write functions
00257     virtual void setNodeValue(const nsAString& nodeValue);
00258 
00259     //Child node manipulation functions
00260     virtual Node* appendChild(Node* newChild);
00261 
00262     MBool hasChildNodes() const;
00263     
00264     //From DOM3 26-Jan-2001 WD
00265     virtual nsresult getBaseURI(nsAString& aURI);
00266 
00267     //Introduced in DOM2
00268     nsresult getNamespaceURI(nsAString& aNSURI);
00269 
00270     //txXPathNode functions
00271     virtual MBool getLocalName(nsIAtom** aLocalName);
00272     virtual PRInt32 getNamespaceID();
00273     virtual PRInt32 lookupNamespaceID(nsIAtom*);
00274     virtual Node* getXPathParent();
00275     virtual PRInt32 compareDocumentPosition(Node* aOther);
00276 
00277     //Inherited from NodeList
00278     Node* item(PRUint32 index);
00279     PRUint32 getLength();
00280 
00281     //Only to be used from XMLParser
00282     void appendData(const PRUnichar* aData, int aLength)
00283     {
00284       nodeValue.Append(aData, aLength);
00285     };
00286 
00287   protected:
00288     friend class Document;
00289     friend class txXPathTreeWalker;
00290     friend class txXPathNodeUtils;
00291     NodeDefinition(NodeType type, const nsAString& name,
00292                    const nsAString& value, Document* owner);
00293     NodeDefinition(NodeType aType, const nsAString& aValue,
00294                    Document* aOwner);
00295 
00296     //Name, value, and attributes for this node.  Available to derrived
00297     //classes, since those derrived classes have a better idea how to use them,
00298     //than the generic node does.
00299     nsString nodeName;
00300     nsString nodeValue;
00301 
00302     NodeDefinition* implAppendChild(NodeDefinition* newChild);
00303     NodeDefinition* implRemoveChild(NodeDefinition* oldChild);
00304 
00305     void DeleteChildren();
00306 
00307   private:
00308     void Init(NodeType aType, const nsAString& aValue, Document* aOwner);
00309 
00310     //Type of node this is
00311     NodeType nodeType;
00312 
00313     //Data members for linking this Node to its parent and siblings
00314     NodeDefinition* parentNode;
00315     NodeDefinition* previousSibling;
00316     NodeDefinition* nextSibling;
00317 
00318     //Pointer to the node's document
00319     Document* ownerDocument;
00320 
00321     //Data members for maintaining a list of child nodes
00322     NodeDefinition* firstChild;
00323     NodeDefinition* lastChild;
00324 
00325     // Struct to hold document order information
00326     struct OrderInfo {
00327         ~OrderInfo();
00328         PRUint32* mOrder;
00329         PRInt32 mSize;
00330         Node* mRoot;
00331     };
00332 
00333     // OrderInfo object for comparing document order
00334     OrderInfo* mOrderInfo;
00335 
00336     // Helperfunction for compareDocumentOrder
00337     OrderInfo* getOrderInfo();
00338 };
00339 
00340 //
00341 //Definition and Implementation of a Document Fragment.  All functionality is
00342 //inherrited directly from NodeDefinition.  We just need to make sure the Type
00343 //of the node set to Node::DOCUMENT_FRAGMENT_NODE.
00344 //
00345 class DocumentFragment : public NodeDefinition
00346 {
00347   public:
00348     Node* appendChild(Node* newChild)
00349     {
00350       switch (newChild->getNodeType())
00351         {
00352           case Node::ELEMENT_NODE :
00353           case Node::TEXT_NODE :
00354           case Node::COMMENT_NODE :
00355           case Node::PROCESSING_INSTRUCTION_NODE :
00356             {
00357               // Remove the "newChild" if it is already a child of this node
00358               NodeDefinition* pNewChild = (NodeDefinition*)newChild;
00359               if (pNewChild->getParentNode() == this)
00360                 pNewChild = implRemoveChild(pNewChild);
00361 
00362               return implAppendChild(pNewChild);
00363             }
00364 
00365           default:
00366             break;
00367         }
00368 
00369       return nsnull;
00370     };
00371 
00372   private:
00373     friend class Document;
00374     DocumentFragment(Document* aOwner) :
00375       NodeDefinition(Node::DOCUMENT_FRAGMENT_NODE, EmptyString(), aOwner)
00376     {
00377     };
00378 };
00379 
00380 //
00381 //Definition and Implementation of a Document.
00382 //
00383 
00393 class txIDEntry : public PLDHashStringEntry
00394 {
00395 public:
00396     txIDEntry(const void* aKey) : PLDHashStringEntry(aKey), mElement(nsnull)
00397     {
00398     }
00399     ~txIDEntry()
00400     {
00401     }
00402     Element* mElement;
00403 };
00404 DECL_DHASH_WRAPPER(txIDMap, txIDEntry, nsAString&)
00405 
00406 class Document : public NodeDefinition
00407 {
00408   public:
00409     Document();
00410 
00411     Element* getDocumentElement();
00412 
00413     //Factory functions for various node types
00414     Node* createComment(const nsAString& aData);
00415     Node* createDocumentFragment();
00416     ProcessingInstruction* createProcessingInstruction(const nsAString& aTarget,
00417                                                        const nsAString& aData);
00418     Node* createTextNode(const nsAString& theData);
00419 
00420     Element* createElement(const nsAString& tagName);
00421     Attr* createAttribute(const nsAString& name);
00422 
00423     // Introduced in DOM Level 2
00424     Element* createElementNS(const nsAString& aNamespaceURI,
00425                              const nsAString& aTagName);
00426     Attr* createAttributeNS(const nsAString& aNamespaceURI,
00427                             const nsAString& aName);
00428     Element* getElementById(const nsAString& aID);
00429 
00430     // Node manipulation functions
00431     Node* appendChild(Node* newChild);
00432 
00433     //Override to return documentBaseURI
00434     nsresult getBaseURI(nsAString& aURI);
00435 
00436   private:
00437     PRBool setElementID(const nsAString& aID, Element* aElement);
00438 
00439     Element* documentElement;
00440 
00441     // This class is friend to be able to set the documentBaseURI
00442     // and IDs.
00443     friend class txXMLParser;
00444     txIDMap mIDMap;
00445     nsString documentBaseURI;
00446 };
00447 
00448 //
00449 //Definition and Implementation of an Element
00450 //
00451 class Element : public NodeDefinition
00452 {
00453   public:
00454     virtual ~Element();
00455 
00456     NamedNodeMap* getAttributes();
00457     void setAttribute(const nsAString& name, const nsAString& value);
00458     void setAttributeNS(const nsAString& aNamespaceURI,
00459                         const nsAString& aName,
00460                         const nsAString& aValue);
00461     Attr* getAttributeNode(const nsAString& name);
00462 
00463     // Node manipulation functions
00464     Node* appendChild(Node* newChild);
00465 
00466     //txXPathNode functions override
00467     MBool getLocalName(nsIAtom** aLocalName);
00468     PRInt32 getNamespaceID();
00469     MBool getAttr(nsIAtom* aLocalName, PRInt32 aNSID, nsAString& aValue);
00470     MBool hasAttr(nsIAtom* aLocalName, PRInt32 aNSID);
00471 
00472     // ID getter
00473     PRBool getIDValue(nsAString& aValue);
00474 
00475   private:
00476     friend class Document;
00477     void setIDValue(const nsAString& aValue);
00478     Element(const nsAString& tagName, Document* owner);
00479     Element(const nsAString& aNamespaceURI, const nsAString& aTagName,
00480             Document* aOwner);
00481 
00482     AttrMap mAttributes;
00483     nsString mIDValue;
00484     nsCOMPtr<nsIAtom> mLocalName;
00485     PRInt32 mNamespaceID;
00486 };
00487 
00488 //
00489 //Definition and Implementation of a Attr
00490 //    NOTE:  For the time bing use just the default functionality found in the
00491 //           NodeDefinition class
00492 //
00493 class Attr : public NodeDefinition
00494 {
00495   public:
00496     virtual ~Attr();
00497 
00498     //Override the set and get member functions for a node's value to create a
00499     //new TEXT node when set, and to interpret its children when read.
00500     void setNodeValue(const nsAString& aValue);
00501     nsresult getNodeValue(nsAString& aValue);
00502 
00503     // Node manipulation functions
00504     Node* appendChild(Node* newChild);
00505 
00506     //txXPathNode functions override
00507     MBool getLocalName(nsIAtom** aLocalName);
00508     PRInt32 getNamespaceID();
00509     Node* getXPathParent();
00510 
00511   private:
00512     friend class Document;
00513     Attr(const nsAString& name, Document* owner);
00514     Attr(const nsAString& aNamespaceURI, const nsAString& aName,
00515          Document* aOwner);
00516 
00517     // These need to be friend to be able to update the ownerElement
00518     friend class AttrMap;
00519     friend class Element;
00520 
00521     Element* ownerElement;
00522 
00523     nsCOMPtr<nsIAtom> mLocalName;
00524     PRInt32 mNamespaceID;
00525 };
00526 
00527 //
00528 //Definition and Implemention of a ProcessingInstruction node.  Most
00529 //functionality is inherrited from NodeDefinition.
00530 //  The Target of a processing instruction is stored in the nodeName datamember
00531 //  inherrited from NodeDefinition.
00532 //  The Data of a processing instruction is stored in the nodeValue datamember
00533 //  inherrited from NodeDefinition
00534 //
00535 class ProcessingInstruction : public NodeDefinition
00536 {
00537   public:
00538     ~ProcessingInstruction();
00539 
00540     //txXPathNode functions override
00541     MBool getLocalName(nsIAtom** aLocalName);
00542 
00543   private:
00544     friend class Document;
00545     ProcessingInstruction(const nsAString& theTarget, const nsAString& theData,
00546                           Document* owner);
00547 
00548     nsCOMPtr<nsIAtom> mLocalName;
00549 };
00550 
00551 class txStandaloneNamespaceManager
00552 {
00553 public:
00554     static PRInt32 getNamespaceID(const nsAString& aURI)
00555     {
00556         if (!mNamespaces && !init())
00557             return kNameSpaceID_Unknown;
00558 
00559         PRInt32 id = mNamespaces->IndexOf(aURI);
00560         if (id != -1) {
00561             return id + 1;
00562         }
00563 
00564         if (!mNamespaces->AppendString(aURI)) {
00565             NS_ASSERTION(0, "Out of memory, namespaces are getting lost");
00566             return kNameSpaceID_Unknown;
00567         }
00568 
00569         return mNamespaces->Count();
00570     }
00571 
00572     static nsresult getNamespaceURI(const PRInt32 aID, nsAString& aNSURI)
00573     {
00574         // empty namespace, and errors
00575         aNSURI.Truncate();
00576         if (aID <= 0 || (!mNamespaces && !init()) ||
00577             aID > mNamespaces->Count()) {
00578             return NS_OK;
00579         }
00580 
00581         aNSURI = *mNamespaces->StringAt(aID - 1);
00582         return NS_OK;
00583     }
00584 
00585     static MBool init()
00586     {
00587         NS_ASSERTION(!mNamespaces,
00588                      "called without matching shutdown()");
00589         if (mNamespaces)
00590             return MB_TRUE;
00591         mNamespaces = new nsStringArray();
00592         if (!mNamespaces)
00593             return MB_FALSE;
00594         /*
00595          * Hardwiring some Namespace IDs.
00596          * no Namespace is 0
00597          * xmlns prefix is 1, mapped to http://www.w3.org/2000/xmlns/
00598          * xml prefix is 2, mapped to http://www.w3.org/XML/1998/namespace
00599          */
00600         if (!mNamespaces->AppendString(NS_LITERAL_STRING("http://www.w3.org/2000/xmlns/")) ||
00601             !mNamespaces->AppendString(NS_LITERAL_STRING("http://www.w3.org/XML/1998/namespace")) ||
00602             !mNamespaces->AppendString(NS_LITERAL_STRING("http://www.w3.org/1999/XSL/Transform"))) {
00603             delete mNamespaces;
00604             mNamespaces = 0;
00605             return MB_FALSE;
00606         }
00607 
00608         return MB_TRUE;
00609     }
00610 
00611     static void shutdown()
00612     {
00613         NS_ASSERTION(mNamespaces, "called without matching init()");
00614         if (!mNamespaces)
00615             return;
00616         delete mNamespaces;
00617         mNamespaces = nsnull;
00618     }
00619 
00620 private:
00621     static nsStringArray* mNamespaces;
00622 };
00623 
00624 #define TX_IMPL_DOM_STATICS \
00625     nsStringArray* txStandaloneNamespaceManager::mNamespaces = 0
00626 
00627 #endif