KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xerces > internal > dom > ElementImpl


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 1999, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58 package com.sun.org.apache.xerces.internal.dom;
59
60 import org.w3c.dom.Attr JavaDoc;
61 import org.w3c.dom.DOMException JavaDoc;
62 import org.w3c.dom.Element JavaDoc;
63 import org.w3c.dom.NamedNodeMap JavaDoc;
64 import org.w3c.dom.Node JavaDoc;
65 import org.w3c.dom.NodeList JavaDoc;
66 import org.w3c.dom.Text JavaDoc;
67 import org.w3c.dom.TypeInfo JavaDoc;
68
69 import com.sun.org.apache.xerces.internal.util.URI;
70
71 /**
72  * Elements represent most of the "markup" and structure of the
73  * document. They contain both the data for the element itself
74  * (element name and attributes), and any contained nodes, including
75  * document text (as children).
76  * <P>
77  * Elements may have Attributes associated with them; the API for this is
78  * defined in Node, but the function is implemented here. In general, XML
79  * applications should retrive Attributes as Nodes, since they may contain
80  * entity references and hence be a fairly complex sub-tree. HTML users will
81  * be dealing with simple string values, and convenience methods are provided
82  * to work in terms of Strings.
83  * <P>
84  * ElementImpl does not support Namespaces. ElementNSImpl, which inherits from
85  * it, does.
86  * @see ElementNSImpl
87  *
88  * @author Arnaud Le Hors, IBM
89  * @author Joe Kesselman, IBM
90  * @author Andy Clark, IBM
91  * @author Ralf Pfeiffer, IBM
92  * @version $Id: ElementImpl.java,v 1.1.2.2 2006/10/11 19:21:01 spericas Exp $
93  * @since PR-DOM-Level-1-19980818.
94  */

95 public class ElementImpl
96     extends ParentNode
97     implements Element JavaDoc {
98
99     //
100
// Constants
101
//
102

103     /** Serialization version. */
104     static final long serialVersionUID = 3717253516652722278L;
105     //
106
// Data
107
//
108

109     /** Element name. */
110     protected String JavaDoc name;
111
112     /** Attributes. */
113     protected AttributeMap attributes;
114     
115     /** DOM3: type information */
116     // REVISIT: we are losing the type information in DOM during serialization
117
transient TypeInfo JavaDoc type;
118
119     //
120
// Constructors
121
//
122

123     /** Factory constructor. */
124     public ElementImpl(CoreDocumentImpl ownerDoc, String JavaDoc name) {
125         super(ownerDoc);
126         this.name = name;
127         needsSyncData(true); // synchronizeData will initialize attributes
128
}
129
130     // for ElementNSImpl
131
protected ElementImpl() {}
132     
133     // Support for DOM Level 3 renameNode method.
134
// Note: This only deals with part of the pb. CoreDocumentImpl
135
// does all the work.
136
void rename(String JavaDoc name) {
137         if (needsSyncData()) {
138             synchronizeData();
139         }
140         this.name = name;
141         reconcileDefaultAttributes();
142     }
143
144     //
145
// Node methods
146
//
147

148     
149     /**
150      * A short integer indicating what type of node this is. The named
151      * constants for this value are defined in the org.w3c.dom.Node interface.
152      */

153     public short getNodeType() {
154         return Node.ELEMENT_NODE;
155     }
156
157     /**
158      * Returns the element name
159      */

160     public String JavaDoc getNodeName() {
161         if (needsSyncData()) {
162             synchronizeData();
163         }
164         return name;
165     }
166
167     /**
168      * Retrieve all the Attributes as a set. Note that this API is inherited
169      * from Node rather than specified on Element; in fact only Elements will
170      * ever have Attributes, but they want to allow folks to "blindly" operate
171      * on the tree as a set of Nodes.
172      */

173     public NamedNodeMap JavaDoc getAttributes() {
174
175         if (needsSyncData()) {
176             synchronizeData();
177         }
178         if (attributes == null) {
179             attributes = new AttributeMap(this, null);
180         }
181         return attributes;
182
183     } // getAttributes():NamedNodeMap
184

185     /**
186      * Return a duplicate copy of this Element. Note that its children
187      * will not be copied unless the "deep" flag is true, but Attributes
188      * are <i>always</i> replicated.
189      *
190      * @see org.w3c.dom.Node#cloneNode(boolean)
191      */

192     public Node JavaDoc cloneNode(boolean deep) {
193
194         ElementImpl newnode = (ElementImpl) super.cloneNode(deep);
195         // Replicate NamedNodeMap rather than sharing it.
196
if (attributes != null) {
197             newnode.attributes = (AttributeMap) attributes.cloneMap(newnode);
198         }
199         return newnode;
200
201     } // cloneNode(boolean):Node
202

203    /**
204      * DOM Level 3 WD - Experimental.
205      * Retrieve baseURI
206      */

207     public String JavaDoc getBaseURI() {
208
209         if (needsSyncData()) {
210             synchronizeData();
211         }
212         // Absolute base URI is computed according to
213
// XML Base (http://www.w3.org/TR/xmlbase/#granularity)
214
// 1. The base URI specified by an xml:base attribute on the element,
215
// if one exists
216
if (attributes != null) {
217             Attr JavaDoc attrNode = (Attr JavaDoc)attributes.getNamedItem("xml:base");
218             if (attrNode != null) {
219                 String JavaDoc uri = attrNode.getNodeValue();
220                 if (uri.length() != 0 ) {// attribute value is always empty string
221
try {
222                        uri = new URI(uri).toString();
223                     }
224                     catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException e){
225                         return null;
226                     }
227                     return uri;
228                 }
229             }
230         }
231
232         // 2.the base URI of the element's parent element within the
233
// document or external entity, if one exists
234
// 3. the base URI of the document entity or external entity
235
// containing the element
236

237         // ownerNode serves as a parent or as document
238
String JavaDoc baseURI = (this.ownerNode != null) ? this.ownerNode.getBaseURI() : null ;
239         //base URI of parent element is not null
240
if(baseURI != null){
241             try {
242                 //return valid absolute base URI
243
return new URI(baseURI).toString();
244             }
245             catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException e){
246                 return null;
247             }
248         }
249         return null;
250     } //getBaseURI
251

252
253
254     /**
255      * NON-DOM
256      * set the ownerDocument of this node, its children, and its attributes
257      */

258     void setOwnerDocument(CoreDocumentImpl doc) {
259     super.setOwnerDocument(doc);
260         if (attributes != null) {
261             attributes.setOwnerDocument(doc);
262         }
263     }
264
265     //
266
// Element methods
267
//
268

269     /**
270      * Look up a single Attribute by name. Returns the Attribute's
271      * string value, or an empty string (NOT null!) to indicate that the
272      * name did not map to a currently defined attribute.
273      * <p>
274      * Note: Attributes may contain complex node trees. This method
275      * returns the "flattened" string obtained from Attribute.getValue().
276      * If you need the structure information, see getAttributeNode().
277      */

278     public String JavaDoc getAttribute(String JavaDoc name) {
279
280         if (needsSyncData()) {
281             synchronizeData();
282         }
283         if (attributes == null) {
284             return "";
285         }
286         Attr JavaDoc attr = (Attr JavaDoc)(attributes.getNamedItem(name));
287         return (attr == null) ? "" : attr.getValue();
288
289     } // getAttribute(String):String
290

291
292     /**
293      * Look up a single Attribute by name. Returns the Attribute Node,
294      * so its complete child tree is available. This could be important in
295      * XML, where the string rendering may not be sufficient information.
296      * <p>
297      * If no matching attribute is available, returns null.
298      */

299     public Attr JavaDoc getAttributeNode(String JavaDoc name) {
300
301         if (needsSyncData()) {
302             synchronizeData();
303         }
304         if (attributes == null) {
305             return null;
306         }
307         return (Attr JavaDoc)attributes.getNamedItem(name);
308
309     } // getAttributeNode(String):Attr
310

311
312     /**
313      * Returns a NodeList of all descendent nodes (children,
314      * grandchildren, and so on) which are Elements and which have the
315      * specified tag name.
316      * <p>
317      * Note: NodeList is a "live" view of the DOM. Its contents will
318      * change as the DOM changes, and alterations made to the NodeList
319      * will be reflected in the DOM.
320      *
321      * @param tagname The type of element to gather. To obtain a list of
322      * all elements no matter what their names, use the wild-card tag
323      * name "*".
324      *
325      * @see DeepNodeListImpl
326      */

327     public NodeList JavaDoc getElementsByTagName(String JavaDoc tagname) {
328         return new DeepNodeListImpl(this,tagname);
329     }
330
331     /**
332      * Returns the name of the Element. Note that Element.nodeName() is
333      * defined to also return the tag name.
334      * <p>
335      * This is case-preserving in XML. HTML should uppercasify it on the
336      * way in.
337      */

338     public String JavaDoc getTagName() {
339         if (needsSyncData()) {
340             synchronizeData();
341         }
342         return name;
343     }
344
345     /**
346      * In "normal form" (as read from a source file), there will never be two
347      * Text children in succession. But DOM users may create successive Text
348      * nodes in the course of manipulating the document. Normalize walks the
349      * sub-tree and merges adjacent Texts, as if the DOM had been written out
350      * and read back in again. This simplifies implementation of higher-level
351      * functions that may want to assume that the document is in standard form.
352      * <p>
353      * To normalize a Document, normalize its top-level Element child.
354      * <p>
355      * As of PR-DOM-Level-1-19980818, CDATA -- despite being a subclass of
356      * Text -- is considered "markup" and will _not_ be merged either with
357      * normal Text or with other CDATASections.
358      */

359     public void normalize() {
360         // No need to normalize if already normalized.
361
if (isNormalized()) {
362             return;
363         }
364         if (needsSyncChildren()) {
365             synchronizeChildren();
366         }
367         ChildNode kid, next;
368         for (kid = firstChild; kid != null; kid = next) {
369             next = kid.nextSibling;
370
371             // If kid is a text node, we need to check for one of two
372
// conditions:
373
// 1) There is an adjacent text node
374
// 2) There is no adjacent text node, but kid is
375
// an empty text node.
376
if ( kid.getNodeType() == Node.TEXT_NODE )
377             {
378                 // If an adjacent text node, merge it with kid
379
if ( next!=null && next.getNodeType() == Node.TEXT_NODE )
380                 {
381                     ((Text JavaDoc)kid).appendData(next.getNodeValue());
382                     removeChild( next );
383                     next = kid; // Don't advance; there might be another.
384
}
385                 else
386                 {
387                     // If kid is empty, remove it
388
if ( kid.getNodeValue().length()==0 )
389                         removeChild( kid );
390                 }
391             }
392
393             // Otherwise it might be an Element, which is handled recursively
394
else if (kid.getNodeType() == Node.ELEMENT_NODE) {
395                 kid.normalize();
396             }
397         }
398
399         // We must also normalize all of the attributes
400
if ( attributes!=null )
401         {
402             for( int i=0; i<attributes.getLength(); ++i )
403             {
404                 Node JavaDoc attr = attributes.item(i);
405                 attr.normalize();
406             }
407         }
408
409         // changed() will have occurred when the removeChild() was done,
410
// so does not have to be reissued.
411

412         isNormalized(true);
413     } // normalize()
414

415     /**
416      * Remove the named attribute from this Element. If the removed
417      * Attribute has a default value, it is immediately replaced thereby.
418      * <P>
419      * The default logic is actually implemented in NamedNodeMapImpl.
420      * PR-DOM-Level-1-19980818 doesn't fully address the DTD, so some
421      * of this behavior is likely to change in future versions. ?????
422      * <P>
423      * Note that this call "succeeds" even if no attribute by this name
424      * existed -- unlike removeAttributeNode, which will throw a not-found
425      * exception in that case.
426      *
427      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is
428      * readonly.
429      */

430     public void removeAttribute(String JavaDoc name) {
431
432         if (ownerDocument.errorChecking && isReadOnly()) {
433             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
434             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
435         }
436             
437         if (needsSyncData()) {
438             synchronizeData();
439         }
440
441         if (attributes == null) {
442             return;
443         }
444
445         attributes.safeRemoveNamedItem(name);
446
447     } // removeAttribute(String)
448

449   
450     /**
451      * Remove the specified attribute/value pair. If the removed
452      * Attribute has a default value, it is immediately replaced.
453      * <p>
454      * NOTE: Specifically removes THIS NODE -- not the node with this
455      * name, nor the node with these contents. If the specific Attribute
456      * object passed in is not stored in this Element, we throw a
457      * DOMException. If you really want to remove an attribute by name,
458      * use removeAttribute().
459      *
460      * @return the Attribute object that was removed.
461      * @throws DOMException(NOT_FOUND_ERR) if oldattr is not an attribute of
462      * this Element.
463      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is
464      * readonly.
465      */

466     public Attr JavaDoc removeAttributeNode(Attr JavaDoc oldAttr)
467         throws DOMException JavaDoc {
468
469         if (ownerDocument.errorChecking && isReadOnly()) {
470             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
471             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
472         }
473             
474         if (needsSyncData()) {
475             synchronizeData();
476         }
477
478         if (attributes == null) {
479             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
480             throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
481         }
482         return (Attr JavaDoc) attributes.removeItem(oldAttr, true);
483
484     } // removeAttributeNode(Attr):Attr
485

486    
487     /**
488      * Add a new name/value pair, or replace the value of the existing
489      * attribute having that name.
490      *
491      * Note: this method supports only the simplest kind of Attribute,
492      * one whose value is a string contained in a single Text node.
493      * If you want to assert a more complex value (which XML permits,
494      * though HTML doesn't), see setAttributeNode().
495      *
496      * The attribute is created with specified=true, meaning it's an
497      * explicit value rather than inherited from the DTD as a default.
498      * Again, setAttributeNode can be used to achieve other results.
499      *
500      * @throws DOMException(INVALID_NAME_ERR) if the name is not acceptable.
501      * (Attribute factory will do that test for us.)
502      *
503      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is
504      * readonly.
505      */

506     public void setAttribute(String JavaDoc name, String JavaDoc value) {
507
508         if (ownerDocument.errorChecking && isReadOnly()) {
509             String JavaDoc msg =
510                 DOMMessageFormatter.formatMessage(
511                     DOMMessageFormatter.DOM_DOMAIN,
512                     "NO_MODIFICATION_ALLOWED_ERR",
513                     null);
514             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
515         }
516
517         if (needsSyncData()) {
518             synchronizeData();
519         }
520
521         Attr JavaDoc newAttr = getAttributeNode(name);
522         if (newAttr == null) {
523             newAttr = getOwnerDocument().createAttribute(name);
524
525             if (attributes == null) {
526                 attributes = new AttributeMap(this, null);
527             }
528
529             newAttr.setNodeValue(value);
530             attributes.setNamedItem(newAttr);
531         }
532         else {
533             newAttr.setNodeValue(value);
534         }
535
536     } // setAttribute(String,String)
537

538     /**
539      * Add a new attribute/value pair, or replace the value of the
540      * existing attribute with that name.
541      * <P>
542      * This method allows you to add an Attribute that has already been
543      * constructed, and hence avoids the limitations of the simple
544      * setAttribute() call. It can handle attribute values that have
545      * arbitrarily complex tree structure -- in particular, those which
546      * had entity references mixed into their text.
547      *
548      * @throws DOMException(INUSE_ATTRIBUTE_ERR) if the Attribute object
549      * has already been assigned to another Element.
550      */

551     public Attr JavaDoc setAttributeNode(Attr JavaDoc newAttr)
552         throws DOMException JavaDoc
553         {
554
555         if (needsSyncData()) {
556             synchronizeData();
557         }
558
559         if (ownerDocument.errorChecking) {
560             if (isReadOnly()) {
561                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
562                 throw new DOMException JavaDoc(
563                                      DOMException.NO_MODIFICATION_ALLOWED_ERR,
564                                      msg);
565             }
566         
567             if (newAttr.getOwnerDocument() != ownerDocument) {
568                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
569                 throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR, msg);
570             }
571         }
572
573         if (attributes == null) {
574             attributes = new AttributeMap(this, null);
575         }
576         // This will throw INUSE if necessary
577
return (Attr JavaDoc) attributes.setNamedItem(newAttr);
578
579     } // setAttributeNode(Attr):Attr
580

581     //
582
// DOM2: Namespace methods
583
//
584

585     /**
586      * Introduced in DOM Level 2. <p>
587      *
588      * Retrieves an attribute value by local name and namespace URI.
589      *
590      * @param namespaceURI
591      * The namespace URI of the attribute to
592      * retrieve.
593      * @param localName The local name of the attribute to retrieve.
594      * @return String The Attr value as a string, or empty string
595      * if that attribute
596      * does not have a specified or default value.
597      * @since WD-DOM-Level-2-19990923
598      */

599     public String JavaDoc getAttributeNS(String JavaDoc namespaceURI, String JavaDoc localName) {
600
601         if (needsSyncData()) {
602             synchronizeData();
603         }
604
605         if (attributes == null) {
606             return "";
607         }
608
609         Attr JavaDoc attr = (Attr JavaDoc)(attributes.getNamedItemNS(namespaceURI, localName));
610         return (attr == null) ? "" : attr.getValue();
611
612     } // getAttributeNS(String,String):String
613

614     /**
615      * Introduced in DOM Level 2. <p>
616      *
617      * Adds a new attribute.
618      * If the given namespaceURI is null or an empty string and the
619      * qualifiedName has a prefix that is "xml", the new attribute is bound to
620      * the predefined namespace "http://www.w3.org/XML/1998/namespace"
621      * [Namespaces]. If an attribute with the same local name and namespace
622      * URI is already present on the element, its prefix is changed to be the
623      * prefix part of the qualifiedName, and its value is changed to be the
624      * value parameter. This value is a simple string, it is not parsed as it
625      * is being set. So any markup (such as syntax to be recognized as an
626      * entity reference) is treated as literal text, and needs to be
627      * appropriately escaped by the implementation when it is written out. In
628      * order to assign an attribute value that contains entity references, the
629      * user must create an Attr node plus any Text and EntityReference nodes,
630      * build the appropriate subtree, and use setAttributeNodeNS or
631      * setAttributeNode to assign it as the value of an attribute.
632      *
633      * @param namespaceURI The namespace URI of the attribute to create
634      * or alter.
635      * @param qualifiedName The qualified name of the attribute to create or
636      * alter.
637      * @param value The value to set in string form.
638      * @throws INVALID_CHARACTER_ERR: Raised if the specified
639      * name contains an invalid character.
640      *
641      * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if this
642      * node is readonly.
643      *
644      * @throws NAMESPACE_ERR: Raised if the qualifiedName
645      * has a prefix that is "xml" and the namespaceURI
646      * is neither null nor an empty string nor
647      * "http://www.w3.org/XML/1998/namespace", or if
648      * the qualifiedName has a prefix that is "xmlns"
649      * but the namespaceURI is neither null nor an
650      * empty string, or if if the qualifiedName has a
651      * prefix different from "xml" and "xmlns" and the
652      * namespaceURI is null or an empty string.
653      * @since WD-DOM-Level-2-19990923
654      */

655      public void setAttributeNS(String JavaDoc namespaceURI,String JavaDoc qualifiedName,
656                                   String JavaDoc value) {
657         if (ownerDocument.errorChecking && isReadOnly()) {
658             String JavaDoc msg =
659                 DOMMessageFormatter.formatMessage(
660                     DOMMessageFormatter.DOM_DOMAIN,
661                     "NO_MODIFICATION_ALLOWED_ERR",
662                     null);
663             throw new DOMException JavaDoc(
664                 DOMException.NO_MODIFICATION_ALLOWED_ERR,
665                 msg);
666         }
667         if (needsSyncData()) {
668             synchronizeData();
669         }
670         int index = qualifiedName.indexOf(':');
671         String JavaDoc prefix, localName;
672         if (index < 0) {
673             prefix = null;
674             localName = qualifiedName;
675         }
676         else {
677             prefix = qualifiedName.substring(0, index);
678             localName = qualifiedName.substring(index + 1);
679         }
680         Attr JavaDoc newAttr = getAttributeNodeNS(namespaceURI, localName);
681         if (newAttr == null) {
682             // REVISIT: this is not efficient, we are creating twice the same
683
// strings for prefix and localName.
684
newAttr = getOwnerDocument().createAttributeNS(
685                     namespaceURI,
686                     qualifiedName);
687             if (attributes == null) {
688                 attributes = new AttributeMap(this, null);
689             }
690             newAttr.setNodeValue(value);
691             attributes.setNamedItemNS(newAttr);
692         }
693         else {
694             if (newAttr instanceof AttrNSImpl){
695                 // change prefix and value
696
((AttrNSImpl)newAttr).name= (prefix!=null)?(prefix+":"+localName):localName;
697             }
698             else {
699                 // This case may happen if user calls:
700
// elem.setAttribute("name", "value");
701
// elem.setAttributeNS(null, "name", "value");
702
// This case is not defined by the DOM spec, we choose
703
// to create a new attribute in this case and remove an old one from the tree
704
// note this might cause events to be propagated or user data to be lost
705
newAttr = new AttrNSImpl((CoreDocumentImpl)getOwnerDocument(), namespaceURI, qualifiedName, localName);
706                 attributes.setNamedItemNS(newAttr);
707             }
708
709             newAttr.setNodeValue(value);
710         }
711
712     } // setAttributeNS(String,String,String)
713

714     
715     /**
716      * Introduced in DOM Level 2. <p>
717      *
718      * Removes an attribute by local name and namespace URI. If the removed
719      * attribute has a default value it is immediately replaced.
720      * The replacing attribute has the same namespace URI and local name,
721      * as well as the original prefix.<p>
722      *
723      * @param namespaceURI The namespace URI of the attribute to remove.
724      *
725      * @param localName The local name of the attribute to remove.
726      * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if this
727      * node is readonly.
728      * @since WD-DOM-Level-2-19990923
729      */

730     public void removeAttributeNS(String JavaDoc namespaceURI, String JavaDoc localName) {
731
732         if (ownerDocument.errorChecking && isReadOnly()) {
733             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
734             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
735         }
736             
737         if (needsSyncData()) {
738             synchronizeData();
739         }
740
741         if (attributes == null) {
742             return;
743         }
744
745         attributes.safeRemoveNamedItemNS(namespaceURI, localName);
746
747     } // removeAttributeNS(String,String)
748

749     /**
750      * Retrieves an Attr node by local name and namespace URI.
751      *
752      * @param namespaceURI The namespace URI of the attribute to
753      * retrieve.
754      * @param localName The local name of the attribute to retrieve.
755      * @return Attr The Attr node with the specified attribute
756      * local name and namespace
757      * URI or null if there is no such attribute.
758      * @since WD-DOM-Level-2-19990923
759      */

760     public Attr JavaDoc getAttributeNodeNS(String JavaDoc namespaceURI, String JavaDoc localName){
761
762         if (needsSyncData()) {
763             synchronizeData();
764         }
765         if (attributes == null) {
766             return null;
767         }
768         return (Attr JavaDoc)attributes.getNamedItemNS(namespaceURI, localName);
769
770     } // getAttributeNodeNS(String,String):Attr
771

772     /**
773      * Introduced in DOM Level 2. <p>
774      *
775      * Adds a new attribute. If an attribute with that local name and
776      * namespace URI is already present in the element, it is replaced
777      * by the new one.
778      *
779      * @param Attr The Attr node to add to the attribute list. When
780      * the Node has no namespaceURI, this method behaves
781      * like setAttributeNode.
782      * @return Attr If the newAttr attribute replaces an existing attribute
783      * with the same local name and namespace URI, the *
784      * previously existing Attr node is returned, otherwise
785      * null is returned.
786      * @throws WRONG_DOCUMENT_ERR: Raised if newAttr
787      * was created from a different document than the one that
788      * created the element.
789      *
790      * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if
791      * this node is readonly.
792      *
793      * @throws INUSE_ATTRIBUTE_ERR: Raised if newAttr is
794      * already an attribute of another Element object. The
795      * DOM user must explicitly clone Attr nodes to re-use
796      * them in other elements.
797      * @since WD-DOM-Level-2-19990923
798      */

799     public Attr JavaDoc setAttributeNodeNS(Attr JavaDoc newAttr)
800         throws DOMException JavaDoc
801         {
802
803         if (needsSyncData()) {
804             synchronizeData();
805         }
806         if (ownerDocument.errorChecking) {
807             if (isReadOnly()) {
808                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
809                 throw new DOMException JavaDoc(
810                                      DOMException.NO_MODIFICATION_ALLOWED_ERR,
811                                      msg);
812             }
813             if (newAttr.getOwnerDocument() != ownerDocument) {
814                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
815                 throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR, msg);
816             }
817         }
818
819         if (attributes == null) {
820             attributes = new AttributeMap(this, null);
821         }
822         // This will throw INUSE if necessary
823
return (Attr JavaDoc) attributes.setNamedItemNS(newAttr);
824
825     } // setAttributeNodeNS(Attr):Attr
826

827     /**
828       * NON-DOM: sets attribute node for this element
829       */

830     protected int setXercesAttributeNode (Attr JavaDoc attr){
831
832         if (needsSyncData()) {
833             synchronizeData();
834         }
835         
836         if (attributes == null) {
837             attributes = new AttributeMap(this, null);
838         }
839         return attributes.addItem(attr);
840
841     }
842     
843     /**
844       * NON-DOM: get inded of an attribute
845       */

846     protected int getXercesAttribute(String JavaDoc namespaceURI, String JavaDoc localName){
847
848         if (needsSyncData()) {
849             synchronizeData();
850         }
851         if (attributes == null) {
852             return -1;
853         }
854         return attributes.getNamedItemIndex(namespaceURI, localName);
855
856     }
857     
858     /**
859      * Introduced in DOM Level 2.
860      */

861     public boolean hasAttributes() {
862         if (needsSyncData()) {
863             synchronizeData();
864         }
865         return (attributes != null && attributes.getLength() != 0);
866     }
867
868     /**
869      * Introduced in DOM Level 2.
870      */

871     public boolean hasAttribute(String JavaDoc name) {
872         return getAttributeNode(name) != null;
873     }
874
875     /**
876      * Introduced in DOM Level 2.
877      */

878     public boolean hasAttributeNS(String JavaDoc namespaceURI, String JavaDoc localName) {
879         return getAttributeNodeNS(namespaceURI, localName) != null;
880     }
881
882     /**
883      * Introduced in DOM Level 2. <p>
884      *
885      * Returns a NodeList of all the Elements with a given local name and
886      * namespace URI in the order in which they would be encountered in a
887      * preorder traversal of the Document tree, starting from this node.
888      *
889      * @param namespaceURI The namespace URI of the elements to match
890      * on. The special value "*" matches all
891      * namespaces. When it is null or an empty
892      * string, this method behaves like
893      * getElementsByTagName.
894      * @param localName The local name of the elements to match on.
895      * The special value "*" matches all local names.
896      * @return NodeList A new NodeList object containing all the matched
897      * Elements.
898      * @since WD-DOM-Level-2-19990923
899      */

900     public NodeList JavaDoc getElementsByTagNameNS(String JavaDoc namespaceURI,
901                                            String JavaDoc localName) {
902         return new DeepNodeListImpl(this, namespaceURI, localName);
903     }
904
905     /**
906      * DOM Level 3 WD- Experimental.
907      * Override inherited behavior from NodeImpl and ParentNode to check on
908      * attributes
909      */

910     public boolean isEqualNode(Node JavaDoc arg) {
911         if (!super.isEqualNode(arg)) {
912             return false;
913         }
914         boolean hasAttrs = hasAttributes();
915         if (hasAttrs != ((Element JavaDoc) arg).hasAttributes()) {
916             return false;
917         }
918         if (hasAttrs) {
919             NamedNodeMap JavaDoc map1 = getAttributes();
920             NamedNodeMap JavaDoc map2 = ((Element JavaDoc) arg).getAttributes();
921             int len = map1.getLength();
922             if (len != map2.getLength()) {
923                 return false;
924             }
925             for (int i = 0; i < len; i++) {
926                 Node JavaDoc n1 = map1.item(i);
927                 if (n1.getLocalName() == null) { // DOM Level 1 Node
928
Node JavaDoc n2 = map2.getNamedItem(n1.getNodeName());
929                     if (n2 == null || !((NodeImpl) n1).isEqualNode(n2)) {
930                         return false;
931                     }
932                 }
933                 else {
934                     Node JavaDoc n2 = map2.getNamedItemNS(n1.getNamespaceURI(),
935                                                   n1.getLocalName());
936                     if (n2 == null || !((NodeImpl) n1).isEqualNode(n2)) {
937                         return false;
938                     }
939                 }
940             }
941         }
942         return true;
943     }
944     
945     /**
946      * DOM Level 3: register the given attribute node as an ID attribute
947      */

948     public void setIdAttributeNode(Attr JavaDoc at, boolean makeId) {
949         if (needsSyncData()) {
950             synchronizeData();
951         }
952         if (ownerDocument.errorChecking) {
953             if (isReadOnly()) {
954                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
955                 throw new DOMException JavaDoc(
956                                      DOMException.NO_MODIFICATION_ALLOWED_ERR,
957                                      msg);
958             }
959         
960             if (at.getOwnerElement() != this) {
961                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
962                 throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
963             }
964         }
965         ((AttrImpl) at).isIdAttribute(makeId);
966         if (!makeId) {
967             ownerDocument.removeIdentifier(at.getValue());
968         }
969         else {
970             ownerDocument.putIdentifier(at.getValue(), this);
971         }
972     }
973     
974     /**
975      * DOM Level 3: register the given attribute node as an ID attribute
976      */

977     public void setIdAttribute(String JavaDoc name, boolean makeId) {
978         if (needsSyncData()) {
979             synchronizeData();
980         }
981         Attr JavaDoc at = getAttributeNode(name);
982         
983         if( at == null){
984             String JavaDoc msg = DOMMessageFormatter.formatMessage(
985                                     DOMMessageFormatter.DOM_DOMAIN,
986                                     "NOT_FOUND_ERR", null);
987             throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
988         }
989         
990         if (ownerDocument.errorChecking) {
991             if (isReadOnly()) {
992                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
993                 throw new DOMException JavaDoc(
994                                      DOMException.NO_MODIFICATION_ALLOWED_ERR,
995                                      msg);
996             }
997         
998             if (at.getOwnerElement() != this) {
999                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
1000                throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
1001            }
1002        }
1003        
1004        ((AttrImpl) at).isIdAttribute(makeId);
1005        if (!makeId) {
1006            ownerDocument.removeIdentifier(at.getValue());
1007        }
1008        else {
1009            ownerDocument.putIdentifier(at.getValue(), this);
1010        }
1011    }
1012
1013    /**
1014     * DOM Level 3: register the given attribute node as an ID attribute
1015     */

1016    public void setIdAttributeNS(String JavaDoc namespaceURI, String JavaDoc localName,
1017                                    boolean makeId) {
1018        if (needsSyncData()) {
1019            synchronizeData();
1020        }
1021        //if namespace uri is empty string, set it to 'null'
1022
if (namespaceURI != null) {
1023            namespaceURI = (namespaceURI.length() == 0)? null : namespaceURI;
1024        }
1025        Attr JavaDoc at = getAttributeNodeNS(namespaceURI, localName);
1026        
1027        if( at == null){
1028            String JavaDoc msg = DOMMessageFormatter.formatMessage(
1029                                    DOMMessageFormatter.DOM_DOMAIN,
1030                                    "NOT_FOUND_ERR", null);
1031            throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
1032        }
1033       
1034        if (ownerDocument.errorChecking) {
1035            if (isReadOnly()) {
1036                String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
1037                throw new DOMException JavaDoc(
1038                                     DOMException.NO_MODIFICATION_ALLOWED_ERR,
1039                                     msg);
1040            }
1041        
1042            if (at.getOwnerElement() != this) {
1043                String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
1044                throw new DOMException JavaDoc(DOMException.NOT_FOUND_ERR, msg);
1045            }
1046        }
1047        ((AttrImpl) at).isIdAttribute(makeId);
1048        if (!makeId) {
1049            ownerDocument.removeIdentifier(at.getValue());
1050        }
1051        else {
1052            ownerDocument.putIdentifier(at.getValue(), this);
1053        }
1054   }
1055
1056    
1057    
1058   /**
1059    * NON-DOM: setting type used by the DOM parser
1060    * @see NodeImpl#setReadOnly
1061    */

1062   public void setType(TypeInfo JavaDoc type) {
1063       this.type = type;
1064   }
1065
1066   /**
1067    * Method getSchemaTypeInfo.
1068    * @return TypeInfo
1069    */

1070   public TypeInfo JavaDoc getSchemaTypeInfo(){
1071       if (needsSyncData()) {
1072           synchronizeData();
1073       }
1074       return type;
1075   }
1076
1077    //
1078
// Public methods
1079
//
1080

1081    /**
1082     * NON-DOM: Subclassed to flip the attributes' readonly switch as well.
1083     * @see NodeImpl#setReadOnly
1084     */

1085    public void setReadOnly(boolean readOnly, boolean deep) {
1086        super.setReadOnly(readOnly,deep);
1087        if (attributes != null) {
1088            attributes.setReadOnly(readOnly,true);
1089        }
1090    }
1091
1092
1093
1094    //
1095
// Protected methods
1096
//
1097

1098    /** Synchronizes the data (name and value) for fast nodes. */
1099    protected void synchronizeData() {
1100
1101        // no need to sync in the future
1102
needsSyncData(false);
1103
1104        // we don't want to generate any event for this so turn them off
1105
boolean orig = ownerDocument.getMutationEvents();
1106        ownerDocument.setMutationEvents(false);
1107
1108        // attributes
1109
setupDefaultAttributes();
1110
1111        // set mutation events flag back to its original value
1112
ownerDocument.setMutationEvents(orig);
1113
1114    } // synchronizeData()
1115

1116    // support for DOM Level 3 renameNode method
1117
// @param el The element from which to take the attributes
1118
void moveSpecifiedAttributes(ElementImpl el) {
1119        if (needsSyncData()) {
1120            synchronizeData();
1121        }
1122        if (el.hasAttributes()) {
1123            if (attributes == null) {
1124                attributes = new AttributeMap(this, null);
1125            }
1126            attributes.moveSpecifiedAttributes(el.attributes);
1127        }
1128    }
1129
1130    /** Setup the default attributes. */
1131    protected void setupDefaultAttributes() {
1132        NamedNodeMapImpl defaults = getDefaultAttributes();
1133        if (defaults != null) {
1134            attributes = new AttributeMap(this, defaults);
1135        }
1136    }
1137
1138    /** Reconcile default attributes. */
1139    protected void reconcileDefaultAttributes() {
1140        if (attributes != null) {
1141            NamedNodeMapImpl defaults = getDefaultAttributes();
1142            attributes.reconcileDefaults(defaults);
1143        }
1144    }
1145
1146    /** Get the default attributes. */
1147    protected NamedNodeMapImpl getDefaultAttributes() {
1148
1149        DocumentTypeImpl doctype =
1150            (DocumentTypeImpl) ownerDocument.getDoctype();
1151        if (doctype == null) {
1152            return null;
1153        }
1154        ElementDefinitionImpl eldef =
1155            (ElementDefinitionImpl)doctype.getElements()
1156                                               .getNamedItem(getNodeName());
1157        if (eldef == null) {
1158            return null;
1159        }
1160        return (NamedNodeMapImpl) eldef.getAttributes();
1161
1162    } // getDefaultAttributes()
1163

1164} // class ElementImpl
1165
Popular Tags