OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / xml / dom / DomAttr.java
1 /* DomAttr.java -- 
2    Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38 package gnu.xml.dom;
39
40 import org.w3c.dom.Attr;
41 import org.w3c.dom.DOMException;
42 import org.w3c.dom.Element;
43 import org.w3c.dom.Node;
44 import org.w3c.dom.TypeInfo;
45 import org.w3c.dom.events.MutationEvent;
46
47
48 /**
49  * <p> "Attr" implementation.  In DOM, attributes cost quite a lot of
50  * memory because their values are complex structures rather than just
51  * simple strings.  To reduce your costs, avoid having more than one
52  * child of an attribute; stick to a single Text node child, and ignore
53  * even that by using the attribute's "nodeValue" property.</p>
54  *
55  * <p> As a bit of general advice, only look at attribute modification
56  * events through the DOMAttrModified event (sent to the associated
57  * element).  Implementations are not guaranteed to report other events
58  * in the same order, so you're very likely to write nonportable code if
59  * you monitor events at the "children of Attr" level.</p>
60  *
61  * <p> At this writing, not all attribute modifications will cause the
62  * DOMAttrModified event to be triggered ... only the ones using the string
63  * methods (setNodeValue, setValue, and Element.setAttribute) to modify
64  * those values.  That is, if you manipulate those children directly,
65  * elements won't get notified that attribute values have changed.
66  * The natural fix for that will report other modifications, but won't 
67  * be able to expose "previous" attribute value; it'll need to be cached
68  * or something (at which point why bother using child nodes). </p>
69  *
70  * <p><em>You are strongly advised not to use "children" of any attribute
71  * nodes you work with.</em> </p>
72  *
73  * @author David Brownell
74  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
75  */
76 public class DomAttr
77   extends DomNsNode
78   implements Attr
79 {
80   
81   private boolean specified;
82   private String value; // string value cache
83   
84   /**
85    * Constructs an Attr node associated with the specified document.
86    * The "specified" flag is initialized to true, since this DOM has
87    * no current "back door" mechanisms to manage default values so
88    * that every value must effectively be "specified".
89    *
90    * <p>This constructor should only be invoked by a Document as part of
91    * its createAttribute functionality, or through a subclass which is
92    * similarly used in a "Sub-DOM" style layer.
93    *
94    * @param owner The document with which this node is associated
95    * @param namespaceURI Combined with the local part of the name,
96    *    this is used to uniquely identify a type of attribute
97    * @param name Name of this attribute, which may include a prefix
98    */
99   protected DomAttr(DomDocument owner, String namespaceURI, String name)
100   {
101     super(ATTRIBUTE_NODE, owner, namespaceURI, name);
102     specified = true;
103     length = 1;
104     
105     // XXX register self to get insertion/removal events
106     // and character data change events and when they happen,
107     // report self-mutation
108   }
109   
110   /**
111    * <b>DOM L1</b>
112    * Returns the attribute name (same as getNodeName)
113    */
114   public final String getName()
115   {
116     return getNodeName();
117   }
118   
119   /**
120    * <b>DOM L1</b>
121    * Returns true if a parser reported this was in the source text.
122    */
123   public final boolean getSpecified()
124   {
125     return specified;
126   }
127   
128   /**
129    * Records whether this attribute was in the source text.
130    */
131   public final void setSpecified(boolean value)
132   {
133     specified = value;
134   }
135
136   /**
137    * <b>DOM L1</b>
138    * Returns the attribute value, with character and entity
139    * references substituted.
140    * <em>NOTE:  entity refs as children aren't currently handled.</em>
141    */
142   public String getNodeValue()
143   {
144     // If we have a simple node-value, use that
145     if (first == null)
146       {
147         return (value == null) ? "" : value;
148       }
149     // Otherwise collect child node-values
150     StringBuffer buf = new StringBuffer();
151     for (DomNode ctx = first; ctx != null; ctx = ctx.next)
152       {
153         switch (ctx.nodeType)
154           {
155           case Node.TEXT_NODE:
156             buf.append(ctx.getNodeValue());
157             break;
158           case Node.ENTITY_REFERENCE_NODE:
159             // TODO
160             break;
161           }
162       }
163     return buf.toString();
164   }
165   
166   /**
167    * <b>DOM L1</b>
168    * Assigns the value of the attribute; it will have one child,
169    * which is a text node with the specified value (same as
170    * setNodeValue).
171    */
172   public final void setValue(String value)
173   {
174     setNodeValue(value);
175   }
176   
177   /**
178    * <b>DOM L1</b>
179    * Returns the value of the attribute as a non-null string; same
180    * as getNodeValue.
181    * <em>NOTE:  entity refs as children aren't currently handled.</em>
182    */
183   public final String getValue()
184   {
185     return getNodeValue();
186   }
187   
188   /**
189    * <b>DOM L1</b>
190    * Assigns the attribute value; using this API, no entity or
191    * character references will exist.
192    * Causes a DOMAttrModified mutation event to be sent.
193    */
194   public void setNodeValue(String value)
195   {
196     if (readonly)
197       {
198         throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR);
199       }
200     if (value == null)
201       {
202         value = "";
203       }
204     String oldValue = getNodeValue();
205     while (last != null)
206       {
207         removeChild(last);
208       }
209     // don't create a new node just for this...
210     /*
211      Node text = owner.createTextNode(value);
212      appendChild(text);
213      */
214     this.value = value;
215     length = 1;
216     specified = true;
217     
218     mutating(oldValue, value, MutationEvent.MODIFICATION);
219   }
220
221   public final Node getFirstChild()
222   {
223     // Create a child text node if necessary
224     if (first == null)
225       {
226         length = 0;
227         Node text = owner.createTextNode((value == null) ? "" : value);
228         appendChild(text);
229       }
230     return first;
231   }
232
233   public final Node getLastChild()
234   {
235     // Create a child text node if necessary
236     if (last == null)
237       {
238         length = 0;
239         Node text = owner.createTextNode((value == null) ? "" : value);
240         appendChild(text);
241       }
242     return last;
243   }
244
245   public Node item(int index)
246   {
247     // Create a child text node if necessary
248     if (first == null)
249       {
250         length = 0;
251         Node text = owner.createTextNode((value == null) ? "" : value);
252         appendChild(text);
253       }
254     return super.item(index);
255   }
256
257   /**
258    * <b>DOM L2</b>
259    * Returns the element with which this attribute is associated.
260    */
261   public final Element getOwnerElement()
262   {
263     return (Element) parent;
264   }
265
266   public final Node getNextSibling()
267   {
268     return null;
269   }
270
271   public final Node getPreviousSibling()
272   {
273     return null;
274   }
275
276   public Node getParentNode()
277   {
278     return null;
279   }
280
281   /**
282    * Records the element with which this attribute is associated.
283    */
284   public final void setOwnerElement(Element e)
285   {
286     if (parent != null)
287       {
288         throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR);
289       }
290     if (!(e instanceof DomElement))
291       {
292         throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR);
293       }
294     parent = (DomElement) e;
295     depth = parent.depth + 1;
296   }
297
298   /**
299    * The base URI of an Attr is always <code>null</code>.
300    */
301   public final String getBaseURI()
302   {
303     return null;
304   }
305     
306   /**
307    * Shallow clone of the attribute, breaking all ties with any
308    * elements.
309    */
310   public Object clone()
311   {
312     DomAttr retval = (DomAttr) super.clone();
313     retval.specified = true;
314     return retval;
315   }
316     
317   private void mutating(String oldValue, String newValue, short why)
318   {
319     if (!reportMutations || parent == null || equal(newValue, oldValue))
320       {
321         return;
322       }
323     
324     // EVENT:  DOMAttrModified, target = parent,
325     //  prev/new values provided, also attr name
326     MutationEvent       event;
327     
328     event = (MutationEvent) createEvent ("MutationEvents");
329     event.initMutationEvent ("DOMAttrModified",
330                              true /* bubbles */, false /* nocancel */,
331                              null, oldValue, newValue, getNodeName (), why);
332     parent.dispatchEvent (event);
333   }
334
335   // DOM Level 3 methods
336   
337   public TypeInfo getSchemaTypeInfo()
338   {
339     if (parent != null)
340       {
341         // DTD implementation
342         DomDoctype doctype = (DomDoctype) parent.owner.getDoctype();
343         if (doctype != null)
344           {
345             return doctype.getAttributeTypeInfo(parent.getNodeName(),
346                                                 getNodeName());
347           }
348         // TODO XML Schema implementation
349       }
350     return null;
351   }
352
353   public boolean isId()
354   {
355     if (parent != null)
356       {
357         DomDoctype doctype = (DomDoctype) parent.owner.getDoctype();
358         if (doctype != null)
359           {
360             DTDAttributeTypeInfo info =
361               doctype.getAttributeTypeInfo(parent.getNodeName(),
362                                            getNodeName());
363             if (info != null && "ID".equals(info.type))
364               {
365                 return true;
366               }
367           }
368         DomElement element = (DomElement) parent;
369         if (element.userIdAttrs != null &&
370             element.userIdAttrs.contains(this))
371           {
372             return true;
373           }
374         // TODO XML Schema implementation
375       }
376     return false;
377   }
378
379 }
380