KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > dom > AttributeMap


1 /*
2  * Copyright 2000-2002,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.xerces.dom;
18
19 import java.util.Vector JavaDoc;
20
21 import org.w3c.dom.DOMException JavaDoc;
22 import org.w3c.dom.Node JavaDoc;
23
24
25 /**
26  * AttributeMap inherits from NamedNodeMapImpl and extends it to deal with the
27  * specifics of storing attributes. These are:
28  * <ul>
29  * <li>managing ownership of attribute nodes
30  * <li>managing default attributes
31  * <li>firing mutation events
32  * </ul>
33  * <p>
34  * This class doesn't directly support mutation events, however, it notifies
35  * the document when mutations are performed so that the document class do so.
36  *
37  * @xerces.internal
38  *
39  * @version $Id: AttributeMap.java,v 1.31 2004/11/04 20:33:37 mrglavas Exp $
40  */

41 public class AttributeMap extends NamedNodeMapImpl {
42     
43     /** Serialization version. */
44     static final long serialVersionUID = 8872606282138665383L;
45
46     //
47
// Constructors
48
//
49

50     /** Constructs a named node map. */
51     protected AttributeMap(ElementImpl ownerNode, NamedNodeMapImpl defaults) {
52         super(ownerNode);
53         if (defaults != null) {
54             // initialize map with the defaults
55
cloneContent(defaults);
56             if (nodes != null) {
57                 hasDefaults(true);
58             }
59         }
60     }
61
62     /**
63      * Adds an attribute using its nodeName attribute.
64      * @see org.w3c.dom.NamedNodeMap#setNamedItem
65      * @return If the new Node replaces an existing node the replaced Node is
66      * returned, otherwise null is returned.
67      * @param arg
68      * An Attr node to store in this map.
69      * @exception org.w3c.dom.DOMException The exception description.
70      */

71     public Node JavaDoc setNamedItem(Node JavaDoc arg)
72     throws DOMException JavaDoc {
73         
74         boolean errCheck = ownerNode.ownerDocument().errorChecking;
75         if (errCheck) {
76             if (isReadOnly()) {
77                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
78                 throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
79             }
80             if (arg.getOwnerDocument() != ownerNode.ownerDocument()) {
81                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
82                 throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR, msg);
83             }
84             if (arg.getNodeType() != Node.ATTRIBUTE_NODE) {
85                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null);
86                 throw new DOMException JavaDoc(DOMException.HIERARCHY_REQUEST_ERR, msg);
87             }
88         }
89         AttrImpl argn = (AttrImpl)arg;
90         
91         if (argn.isOwned()){
92             if (errCheck && argn.getOwnerElement() != ownerNode) {
93                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INUSE_ATTRIBUTE_ERR", null);
94                 throw new DOMException JavaDoc(DOMException.INUSE_ATTRIBUTE_ERR, msg);
95             }
96             // replacing an Attribute with itself does nothing
97
return arg;
98         }
99         
100         
101         // set owner
102
argn.ownerNode = ownerNode;
103         argn.isOwned(true);
104         
105         int i = findNamePoint(arg.getNodeName(),0);
106         AttrImpl previous = null;
107         if (i >= 0) {
108             previous = (AttrImpl) nodes.elementAt(i);
109             nodes.setElementAt(arg,i);
110             previous.ownerNode = ownerNode.ownerDocument();
111             previous.isOwned(false);
112             // make sure it won't be mistaken with defaults in case it's reused
113
previous.isSpecified(true);
114         } else {
115             i = -1 - i; // Insert point (may be end of list)
116
if (null == nodes) {
117                 nodes = new Vector JavaDoc(5, 10);
118             }
119             nodes.insertElementAt(arg, i);
120         }
121         
122         // notify document
123
ownerNode.ownerDocument().setAttrNode(argn, previous);
124         
125         // If the new attribute is not normalized,
126
// the owning element is inherently not normalized.
127
if (!argn.isNormalized()) {
128             ownerNode.isNormalized(false);
129         }
130         return previous;
131         
132     } // setNamedItem(Node):Node
133

134     /**
135      * Adds an attribute using its namespaceURI and localName.
136      * @see org.w3c.dom.NamedNodeMap#setNamedItem
137      * @return If the new Node replaces an existing node the replaced Node is
138      * returned, otherwise null is returned.
139      * @param arg A node to store in a named node map.
140      */

141     public Node JavaDoc setNamedItemNS(Node JavaDoc arg)
142     throws DOMException JavaDoc {
143         
144         boolean errCheck = ownerNode.ownerDocument().errorChecking;
145         if (errCheck) {
146             if (isReadOnly()) {
147                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
148                 throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
149             }
150             if(arg.getOwnerDocument() != ownerNode.ownerDocument()) {
151                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
152                 throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR, msg);
153             }
154             if (arg.getNodeType() != Node.ATTRIBUTE_NODE) {
155                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null);
156                 throw new DOMException JavaDoc(DOMException.HIERARCHY_REQUEST_ERR, msg);
157             }
158         }
159         AttrImpl argn = (AttrImpl)arg;
160         
161         if (argn.isOwned()){
162             if (errCheck && argn.getOwnerElement() != ownerNode) {
163                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INUSE_ATTRIBUTE_ERR", null);
164                 throw new DOMException JavaDoc(DOMException.INUSE_ATTRIBUTE_ERR, msg);
165             }
166             // replacing an Attribute with itself does nothing
167
return arg;
168         }
169         
170         // set owner
171
argn.ownerNode = ownerNode;
172         argn.isOwned(true);
173         
174         int i = findNamePoint(argn.getNamespaceURI(), argn.getLocalName());
175         AttrImpl previous = null;
176         if (i >= 0) {
177             previous = (AttrImpl) nodes.elementAt(i);
178             nodes.setElementAt(arg,i);
179             previous.ownerNode = ownerNode.ownerDocument();
180             previous.isOwned(false);
181             // make sure it won't be mistaken with defaults in case it's reused
182
previous.isSpecified(true);
183         } else {
184             // If we can't find by namespaceURI, localName, then we find by
185
// nodeName so we know where to insert.
186
i = findNamePoint(arg.getNodeName(),0);
187             if (i >=0) {
188                 previous = (AttrImpl) nodes.elementAt(i);
189                 nodes.insertElementAt(arg,i);
190             } else {
191                 i = -1 - i; // Insert point (may be end of list)
192
if (null == nodes) {
193                     nodes = new Vector JavaDoc(5, 10);
194                 }
195                 nodes.insertElementAt(arg, i);
196             }
197         }
198         // changed(true);
199

200         // notify document
201
ownerNode.ownerDocument().setAttrNode(argn, previous);
202         
203         // If the new attribute is not normalized,
204
// the owning element is inherently not normalized.
205
if (!argn.isNormalized()) {
206             ownerNode.isNormalized(false);
207         }
208         return previous;
209         
210     } // setNamedItemNS(Node):Node
211

212     /**
213      * Removes an attribute specified by name.
214      * @param name
215      * The name of a node to remove. If the
216      * removed attribute is known to have a default value, an
217      * attribute immediately appears containing the default value
218      * as well as the corresponding namespace URI, local name,
219      * and prefix when applicable.
220      * @return The node removed from the map if a node with such a name exists.
221      * @throws NOT_FOUND_ERR: Raised if there is no node named
222      * name in the map.
223      */

224     /***/
225     public Node JavaDoc removeNamedItem(String JavaDoc name)
226         throws DOMException JavaDoc {
227         return internalRemoveNamedItem(name, true);
228     }
229
230     /**
231      * Same as removeNamedItem except that it simply returns null if the
232      * specified name is not found.
233      */

234     Node JavaDoc safeRemoveNamedItem(String JavaDoc name) {
235         return internalRemoveNamedItem(name, false);
236     }
237
238
239     /**
240      * NON-DOM: Remove the node object
241      *
242      * NOTE: Specifically removes THIS NODE -- not the node with this
243      * name, nor the node with these contents. If node does not belong to
244      * this named node map, we throw a DOMException.
245      *
246      * @param item The node to remove
247      * @param addDefault true -- magically add default attribute
248      * @return Removed node
249      * @exception DOMException
250      */

251     protected Node JavaDoc removeItem(Node JavaDoc item, boolean addDefault)
252         throws DOMException JavaDoc {
253
254         int index = -1;
255         if (nodes != null) {
256             for (int i = 0; i < nodes.size(); i++) {
257                 if (nodes.elementAt(i) == item) {
258                     index = i;
259                     break;
260                 }
261             }
262         }
263         if (index < 0) {
264             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
265             throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
266         }
267         
268         return remove((AttrImpl)item, index, addDefault);
269     }
270
271     /**
272      * Internal removeNamedItem method allowing to specify whether an exception
273      * must be thrown if the specified name is not found.
274      */

275     final protected Node JavaDoc internalRemoveNamedItem(String JavaDoc name, boolean raiseEx){
276         if (isReadOnly()) {
277                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
278                 throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
279         }
280         int i = findNamePoint(name,0);
281         if (i < 0) {
282             if (raiseEx) {
283                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
284                 throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
285             } else {
286                 return null;
287             }
288         }
289
290         return remove((AttrImpl)nodes.elementAt(i), i, true);
291
292     } // internalRemoveNamedItem(String,boolean):Node
293

294     private final Node JavaDoc remove(AttrImpl attr, int index,
295                               boolean addDefault) {
296
297         CoreDocumentImpl ownerDocument = ownerNode.ownerDocument();
298         String JavaDoc name = attr.getNodeName();
299         if (attr.isIdAttribute()) {
300             ownerDocument.removeIdentifier(attr.getValue());
301         }
302
303         if (hasDefaults() && addDefault) {
304             // If there's a default, add it instead
305
NamedNodeMapImpl defaults =
306                 ((ElementImpl) ownerNode).getDefaultAttributes();
307
308             Node JavaDoc d;
309             if (defaults != null &&
310                 (d = defaults.getNamedItem(name)) != null &&
311                 findNamePoint(name, index+1) < 0) {
312                     NodeImpl clone = (NodeImpl)d.cloneNode(true);
313                     if (d.getLocalName() !=null){
314                             // we must rely on the name to find a default attribute
315
// ("test:attr"), but while copying it from the DOCTYPE
316
// we should not loose namespace URI that was assigned
317
// to the attribute in the instance document.
318
((AttrNSImpl)clone).namespaceURI = attr.getNamespaceURI();
319                     }
320                     clone.ownerNode = ownerNode;
321                     clone.isOwned(true);
322                     clone.isSpecified(false);
323                 
324                     nodes.setElementAt(clone, index);
325                     if (attr.isIdAttribute()) {
326                         ownerDocument.putIdentifier(clone.getNodeValue(),
327                                                 (ElementImpl)ownerNode);
328                     }
329             } else {
330                 nodes.removeElementAt(index);
331             }
332         } else {
333             nodes.removeElementAt(index);
334         }
335
336         // changed(true);
337

338         // remove reference to owner
339
attr.ownerNode = ownerDocument;
340         attr.isOwned(false);
341
342         // make sure it won't be mistaken with defaults in case it's
343
// reused
344
attr.isSpecified(true);
345         attr.isIdAttribute(false);
346
347         // notify document
348
ownerDocument.removedAttrNode(attr, ownerNode, name);
349
350         return attr;
351     }
352     
353     /**
354      * Introduced in DOM Level 2. <p>
355      * Removes an attribute specified by local name and namespace URI.
356      * @param namespaceURI
357      * The namespace URI of the node to remove.
358      * When it is null or an empty string, this
359      * method behaves like removeNamedItem.
360      * @param The local name of the node to remove. If the
361      * removed attribute is known to have a default
362      * value, an attribute immediately appears
363      * containing the default value.
364      * @return Node The node removed from the map if a node with such
365      * a local name and namespace URI exists.
366      * @throws NOT_FOUND_ERR: Raised if there is no node named
367      * name in the map.
368      */

369     public Node JavaDoc removeNamedItemNS(String JavaDoc namespaceURI, String JavaDoc name)
370         throws DOMException JavaDoc {
371         return internalRemoveNamedItemNS(namespaceURI, name, true);
372     }
373
374     /**
375      * Same as removeNamedItem except that it simply returns null if the
376      * specified local name and namespace URI is not found.
377      */

378     Node JavaDoc safeRemoveNamedItemNS(String JavaDoc namespaceURI, String JavaDoc name) {
379         return internalRemoveNamedItemNS(namespaceURI, name, false);
380     }
381
382     /**
383      * Internal removeNamedItemNS method allowing to specify whether an
384      * exception must be thrown if the specified local name and namespace URI
385      * is not found.
386      */

387     final protected Node JavaDoc internalRemoveNamedItemNS(String JavaDoc namespaceURI,
388             String JavaDoc name,
389             boolean raiseEx) {
390         
391         CoreDocumentImpl ownerDocument = ownerNode.ownerDocument();
392         if (ownerDocument.errorChecking && isReadOnly()) {
393             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
394             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
395         }
396         int i = findNamePoint(namespaceURI, name);
397         if (i < 0) {
398             if (raiseEx) {
399                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
400                 throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
401             } else {
402                 return null;
403             }
404         }
405         
406         AttrImpl n = (AttrImpl)nodes.elementAt(i);
407         
408         if (n.isIdAttribute()) {
409             ownerDocument.removeIdentifier(n.getValue());
410         }
411         // If there's a default, add it instead
412
String JavaDoc nodeName = n.getNodeName();
413         if (hasDefaults()) {
414             NamedNodeMapImpl defaults = ((ElementImpl) ownerNode).getDefaultAttributes();
415             Node JavaDoc d;
416             if (defaults != null
417                     && (d = defaults.getNamedItem(nodeName)) != null)
418             {
419                 int j = findNamePoint(nodeName,0);
420                 if (j>=0 && findNamePoint(nodeName, j+1) < 0) {
421                     NodeImpl clone = (NodeImpl)d.cloneNode(true);
422                     clone.ownerNode = ownerNode;
423                     if (d.getLocalName() != null) {
424                         // we must rely on the name to find a default attribute
425
// ("test:attr"), but while copying it from the DOCTYPE
426
// we should not loose namespace URI that was assigned
427
// to the attribute in the instance document.
428
((AttrNSImpl)clone).namespaceURI = namespaceURI;
429                     }
430                     clone.isOwned(true);
431                     clone.isSpecified(false);
432                     nodes.setElementAt(clone, i);
433                     if (clone.isIdAttribute()) {
434                         ownerDocument.putIdentifier(clone.getNodeValue(),
435                                 (ElementImpl)ownerNode);
436                     }
437                 } else {
438                     nodes.removeElementAt(i);
439                 }
440             } else {
441                 nodes.removeElementAt(i);
442             }
443         } else {
444             nodes.removeElementAt(i);
445         }
446         
447         // changed(true);
448

449         // remove reference to owner
450
n.ownerNode = ownerDocument;
451         n.isOwned(false);
452         // make sure it won't be mistaken with defaults in case it's
453
// reused
454
n.isSpecified(true);
455         // update id table if needed
456
n.isIdAttribute(false);
457         
458         // notify document
459
ownerDocument.removedAttrNode(n, ownerNode, name);
460         
461         return n;
462         
463     } // internalRemoveNamedItemNS(String,String,boolean):Node
464

465     //
466
// Public methods
467
//
468

469     /**
470      * Cloning a NamedNodeMap is a DEEP OPERATION; it always clones
471      * all the nodes contained in the map.
472      */

473      
474     public NamedNodeMapImpl cloneMap(NodeImpl ownerNode) {
475         AttributeMap newmap =
476             new AttributeMap((ElementImpl) ownerNode, null);
477         newmap.hasDefaults(hasDefaults());
478         newmap.cloneContent(this);
479         return newmap;
480     } // cloneMap():AttributeMap
481

482     /**
483      * Override parent's method to set the ownerNode correctly
484      */

485     protected void cloneContent(NamedNodeMapImpl srcmap) {
486         Vector JavaDoc srcnodes = srcmap.nodes;
487         if (srcnodes != null) {
488             int size = srcnodes.size();
489             if (size != 0) {
490                 if (nodes == null) {
491                     nodes = new Vector JavaDoc(size);
492                 }
493                 nodes.setSize(size);
494                 for (int i = 0; i < size; ++i) {
495                     NodeImpl n = (NodeImpl) srcnodes.elementAt(i);
496                     NodeImpl clone = (NodeImpl) n.cloneNode(true);
497                     clone.isSpecified(n.isSpecified());
498                     nodes.setElementAt(clone, i);
499                     clone.ownerNode = ownerNode;
500                     clone.isOwned(true);
501                 }
502             }
503         }
504     } // cloneContent():AttributeMap
505

506
507     /**
508      * Move specified attributes from the given map to this one
509      */

510     void moveSpecifiedAttributes(AttributeMap srcmap) {
511         int nsize = (srcmap.nodes != null) ? srcmap.nodes.size() : 0;
512         for (int i = nsize - 1; i >= 0; i--) {
513             AttrImpl attr = (AttrImpl) srcmap.nodes.elementAt(i);
514             if (attr.isSpecified()) {
515                 srcmap.remove(attr, i, false);
516                 if (attr.getLocalName() != null) {
517                     setNamedItem(attr);
518                 }
519                 else {
520                     setNamedItemNS(attr);
521                 }
522             }
523         }
524     } // moveSpecifiedAttributes(AttributeMap):void
525

526
527     /**
528      * Get this AttributeMap in sync with the given "defaults" map.
529      * @param defaults The default attributes map to sync with.
530      */

531     protected void reconcileDefaults(NamedNodeMapImpl defaults) {
532
533         // remove any existing default
534
int nsize = (nodes != null) ? nodes.size() : 0;
535         for (int i = nsize - 1; i >= 0; i--) {
536             AttrImpl attr = (AttrImpl) nodes.elementAt(i);
537             if (!attr.isSpecified()) {
538                 remove(attr, i, false);
539             }
540         }
541         // add the new defaults
542
if (defaults == null) {
543             return;
544         }
545         if (nodes == null || nodes.size() == 0) {
546             cloneContent(defaults);
547         }
548         else {
549             int dsize = defaults.nodes.size();
550             for (int n = 0; n < dsize; n++) {
551                 AttrImpl d = (AttrImpl) defaults.nodes.elementAt(n);
552                 int i = findNamePoint(d.getNodeName(), 0);
553                 if (i < 0) {
554                     i = -1 - i;
555                     NodeImpl clone = (NodeImpl) d.cloneNode(true);
556                     clone.ownerNode = ownerNode;
557                     clone.isOwned(true);
558                     clone.isSpecified(false);
559                     nodes.insertElementAt(clone, i);
560                 }
561             }
562         }
563
564     } // reconcileDefaults()
565

566 } // class AttributeMap
567
Popular Tags