OSDN Git Service

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