summaryrefslogtreecommitdiff
path: root/external/jaxp/source/gnu/xml/dom/DomAttr.java
blob: 7d980d610f9f59027dd29817ef07f8dc58d28c33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/*
 * $Id: DomAttr.java,v 1.1.1.1 2003-02-01 02:10:13 cbj Exp $
 * Copyright (C) 1999-2001 David Brownell
 * 
 * This file is part of GNU JAXP, a library.
 *
 * GNU JAXP is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * GNU JAXP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * As a special exception, if you link this library with other files to
 * produce an executable, this library does not by itself cause the
 * resulting executable to be covered by the GNU General Public License.
 * This exception does not however invalidate any other reasons why the
 * executable file might be covered by the GNU General Public License. 
 */

package gnu.xml.dom;

import org.w3c.dom.*;
import org.w3c.dom.events.MutationEvent;


// $Id: DomAttr.java,v 1.1.1.1 2003-02-01 02:10:13 cbj Exp $

/**
 * <p> "Attr" implementation.  In DOM, attributes cost quite a lot of
 * memory because their values are complex structures rather than just
 * simple strings.  To reduce your costs, avoid having more than one
 * child of an attribute; stick to a single Text node child, and ignore
 * even that by using the attribute's "nodeValue" property.</p>
 *
 * <p> As a bit of general advice, only look at attribute modification
 * events through the DOMAttrModified event (sent to the associated
 * element).  Implementations are not guaranteed to report other events
 * in the same order, so you're very likely to write nonportable code if
 * you monitor events at the "children of Attr" level.</p>
 *
 * <p> At this writing, not all attribute modifications will cause the
 * DOMAttrModified event to be triggered ... only the ones using the string
 * methods (setNodeValue, setValue, and Element.setAttribute) to modify
 * those values.  That is, if you manipulate those children directly,
 * elements won't get notified that attribute values have changed.
 * The natural fix for that will report other modifications, but won't 
 * be able to expose "previous" attribute value; it'll need to be cached
 * or something (at which point why bother using child nodes). </p>
 *
 * <p><em>You are strongly advised not to use "children" of any attribute
 * nodes you work with.</em> </p>
 *
 * @author David Brownell
 * @version $Date: 2003-02-01 02:10:13 $
 */
public class DomAttr extends DomNsNode implements Attr
{
    private boolean	specified;

    // NOTE:  it could be possible to rework this code a bit so that
    // this extra field isn't needed; "parent" might do double duty,
    // with appropriate safeguards.  Using less space is healthy!
    private DomElement	element;


    /**
     * Constructs an Attr node associated with the specified document.
     * The "specified" flag is initialized to true, since this DOM has
     * no current "back door" mechanisms to manage default values so
     * that every value must effectively be "specified".
     *
     * <p>This constructor should only be invoked by a Document as part of
     * its createAttribute functionality, or through a subclass which is
     * similarly used in a "Sub-DOM" style layer.
     *
     * @param owner The document with which this node is associated
     * @param namespaceURI Combined with the local part of the name,
     *	this is used to uniquely identify a type of attribute
     * @param name Name of this attribute, which may include a prefix
     */
    protected DomAttr (Document owner, String namespaceURI, String name)
    {
	super (owner, namespaceURI, name);
	specified = true;

	// XXX register self to get insertion/removal events
	// and character data change events and when they happen,
	// report self-mutation
    }


    /**
     * <b>DOM L1</b>
     * Returns the attribute name (same as getNodeName)
     */
    final public String getName ()
    {
	return getNodeName ();
    }

    /**
     * <b>DOM L1</b>
     * Returns the constant ATTRIBUTE_NODE.
     */
    final public short getNodeType ()
	{ return ATTRIBUTE_NODE; }


    /**
     * <b>DOM L1</b>
     * Returns true if a parser reported this was in the source text.
     */
    final public boolean getSpecified ()
    {
	return specified;
    }


    /**
     * Records whether this attribute was in the source text.
     */
    final public void setSpecified (boolean value)
    {
	specified = value;
    }


    /**
     * <b>DOM L1</b>
     * Returns the attribute value, with character and entity
     * references substituted.
     * <em>NOTE:  entity refs as children aren't currently handled.</em>
     */
    public String getNodeValue ()
    {
	int	length = getLength ();
	String	retval = null;

	for (int i = 0; i < length; i++) {
	    Node	n = item (i);

	    if (n.getNodeType () == TEXT_NODE) {
		if (retval == null)
		    retval = n.getNodeValue ();
		else
		    retval += n.getNodeValue ();
		continue;
	    }
	    
	    // XXX entity ref child of attribute
	    // contents exclude comments, PIs, elements
	    throw new DomEx (DomEx.NOT_SUPPORTED_ERR);
	}
	if (retval == null)
	    retval = "";
	return retval;
    }


    /**
     * <b>DOM L1</b>
     * Assigns the value of the attribute; it will have one child,
     * which is a text node with the specified value (same as
     * setNodeValue).
     */
    final public void setValue (String value)
    {
	setNodeValue (value);
    }


    /**
     * <b>DOM L1</b>
     * Returns the value of the attribute as a non-null string; same
     * as getNodeValue.
     * <em>NOTE:  entity refs as children aren't currently handled.</em>
     */
    final public String getValue ()
    {
	return getNodeValue ();
    }


    /**
     * <b>DOM L1</b>
     * Assigns the attribute value; using this API, no entity or
     * character references will exist.
     * Causes a DOMAttrModified mutation event to be sent.
     */
    public void setNodeValue (String value)
    {
	int	len = getLength ();
	String	oldValue;

	if (isReadonly ())
	    throw new DomEx (DomEx.NO_MODIFICATION_ALLOWED_ERR);

	oldValue = getValue ();
	for (int i = 0; i < len; i++)
	    removeChild (getLastChild ());
	appendChild (getOwnerDocument ().createTextNode (value));
	specified = true;
	
	mutating (oldValue, value, MutationEvent.MODIFICATION);
    }


    /**
     * <b>DOM L2</b>
     * Returns the element with which this attribute is associated.
     */
    final public Element getOwnerElement ()
    {
	return element;
    }


    /**
     * Records the element with which this attribute is associated.
     */
    final public void setOwnerElement (Element e)
    {
	if (element != null)
	    throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR);
	if (!(e instanceof DomElement))
	    throw new DomEx (DomEx.WRONG_DOCUMENT_ERR);
	element = (DomElement) e;
    }


    /**
     * Shallow clone of the attribute, breaking all ties with any
     * elements.
     */
    public Object clone ()
    {
	DomAttr retval = (DomAttr) super.clone ();

	retval.element = null;
	retval.specified = false;
	return retval;
    }

    private void mutating (String oldValue, String newValue, short why)
    {
	if (!reportMutations || element == null)
	    return;

	// EVENT:  DOMAttrModified, target = element,
	//	prev/new values provided, also attr name
	MutationEvent	event;

	event = (MutationEvent) createEvent ("MutationEvents");
	event.initMutationEvent ("DOMAttrModified",
		true /* bubbles */, false /* nocancel */,
		null, oldValue, newValue, getNodeName (), why);
	element.dispatchEvent (event);
    }
}