1 /*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5 /*
6 * Copyright 1999-2004 The Apache Software Foundation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 package com.sun.org.apache.xerces.internal.dom;
22
23 import com.sun.org.apache.xerces.internal.impl.dv.xs.XSSimpleTypeDecl;
24 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
25 import com.sun.org.apache.xerces.internal.xs.XSSimpleTypeDefinition;
26 import org.w3c.dom.DOMException;
27
28 /**
29 * AttrNSImpl inherits from AttrImpl and adds namespace support.
30 * <P>
31 * The qualified name is the node name, and we store localName which is also
32 * used in all queries. On the other hand we recompute the prefix when
33 * necessary.
34 *
35 * @xerces.internal
36 *
37 * @author Arnaud Le Hors, IBM
38 * @author Andy Clark, IBM
39 * @author Ralf Pfeiffer, IBM
40 */
41 public class AttrNSImpl
42 extends AttrImpl {
43
44 //
45 // Constants
46 //
47
48 /** Serialization version. */
49 static final long serialVersionUID = -781906615369795414L;
50
51 static final String xmlnsURI = "http://www.w3.org/2000/xmlns/";
52 static final String xmlURI = "http://www.w3.org/XML/1998/namespace";
53
54 //
55 // Data
56 //
57
58 /** DOM2: Namespace URI. */
59 protected String namespaceURI;
60
61 /** DOM2: localName. */
62 protected String localName;
63
64 /*
65 * Default constructor
66 */
67 public AttrNSImpl(){}
68
69 /**
70 * DOM2: Constructor for Namespace implementation.
71 */
72 protected AttrNSImpl(CoreDocumentImpl ownerDocument,
73 String namespaceURI,
74 String qualifiedName) {
75
76 super(ownerDocument, qualifiedName);
77 setName(namespaceURI, qualifiedName);
78 }
79
80 private void setName(String namespaceURI, String qname){
81 CoreDocumentImpl ownerDocument = ownerDocument();
82 String prefix;
83 // DOM Level 3: namespace URI is never empty string.
84 this.namespaceURI = namespaceURI;
85 if (namespaceURI !=null) {
86 this.namespaceURI = (namespaceURI.length() == 0)? null
87 : namespaceURI;
88
89 }
90 int colon1 = qname.indexOf(':');
91 int colon2 = qname.lastIndexOf(':');
92 ownerDocument.checkNamespaceWF(qname, colon1, colon2);
93 if (colon1 < 0) {
94 // there is no prefix
95 localName = qname;
96 if (ownerDocument.errorChecking) {
97 ownerDocument.checkQName(null, localName);
98
99 if (qname.equals("xmlns") && (namespaceURI == null
100 || !namespaceURI.equals(NamespaceContext.XMLNS_URI))
101 || (namespaceURI!=null && namespaceURI.equals(NamespaceContext.XMLNS_URI)
102 && !qname.equals("xmlns"))) {
103 String msg =
104 DOMMessageFormatter.formatMessage(
105 DOMMessageFormatter.DOM_DOMAIN,
106 "NAMESPACE_ERR",
107 null);
108 throw new DOMException(DOMException.NAMESPACE_ERR, msg);
109 }
110 }
111 }
112 else {
113 prefix = qname.substring(0, colon1);
114 localName = qname.substring(colon2+1);
115 ownerDocument.checkQName(prefix, localName);
116 ownerDocument.checkDOMNSErr(prefix, namespaceURI);
117 }
118 }
119
120 // when local name is known
121 public AttrNSImpl(CoreDocumentImpl ownerDocument,
122 String namespaceURI,
123 String qualifiedName,
124 String localName) {
125 super(ownerDocument, qualifiedName);
126
127 this.localName = localName;
128 this.namespaceURI = namespaceURI;
129 }
130
131 // for DeferredAttrImpl
132 protected AttrNSImpl(CoreDocumentImpl ownerDocument,
133 String value) {
134 super(ownerDocument, value);
135 }
136
137 // Support for DOM Level 3 renameNode method.
138 // Note: This only deals with part of the pb. It is expected to be
139 // called after the Attr has been detached for one thing.
140 // CoreDocumentImpl does all the work.
141 void rename(String namespaceURI, String qualifiedName) {
142 if (needsSyncData()) {
143 synchronizeData();
144 }
145 this.name = qualifiedName;
146 setName(namespaceURI, qualifiedName);
147 }
148
149 /**
150 * NON-DOM: resets this node and sets specified values for the node
151 *
152 * @param ownerDocument
153 * @param namespaceURI
154 * @param qualifiedName
155 * @param localName
156 */
157 public void setValues (CoreDocumentImpl ownerDocument,
158 String namespaceURI,
159 String qualifiedName,
160 String localName){
161
162 super.textNode = null;
163 super.flags = 0;
164 isSpecified(true);
165 hasStringValue(true);
166 super.setOwnerDocument(ownerDocument);
167 this.localName = localName;
168 this.namespaceURI = namespaceURI;
169 super.name = qualifiedName;
170 super.value = null;
171 }
172
173 //
174 // DOM2: Namespace methods
175 //
176
177 /**
178 * Introduced in DOM Level 2. <p>
179 *
180 * The namespace URI of this node, or null if it is unspecified.<p>
181 *
182 * This is not a computed value that is the result of a namespace lookup
183 * based on an examination of the namespace declarations in scope. It is
184 * merely the namespace URI given at creation time.<p>
185 *
186 * For nodes created with a DOM Level 1 method, such as createElement
187 * from the Document interface, this is null.
188 * @since WD-DOM-Level-2-19990923
189 */
190 public String getNamespaceURI()
191 {
192 if (needsSyncData()) {
193 synchronizeData();
194 }
195 // REVIST: This code could/should be done at a lower-level, such that
196 // the namespaceURI is set properly upon creation. However, there still
197 // seems to be some DOM spec interpretation grey-area.
198 return namespaceURI;
199 }
200
201 /**
202 * Introduced in DOM Level 2. <p>
203 *
204 * The namespace prefix of this node, or null if it is unspecified. <p>
205 *
206 * For nodes created with a DOM Level 1 method, such as createElement
207 * from the Document interface, this is null. <p>
208 *
209 * @since WD-DOM-Level-2-19990923
210 */
211 public String getPrefix()
212 {
213 if (needsSyncData()) {
214 synchronizeData();
215 }
216 int index = name.indexOf(':');
217 return index < 0 ? null : name.substring(0, index);
218 }
219
220 /**
221 * Introduced in DOM Level 2. <p>
222 *
223 * Note that setting this attribute changes the nodeName attribute, which
224 * holds the qualified name, as well as the tagName and name attributes of
225 * the Element and Attr interfaces, when applicable.<p>
226 *
227 * @param prefix The namespace prefix of this node, or null(empty string) if it is unspecified.
228 *
229 * @exception INVALID_CHARACTER_ERR
230 * Raised if the specified
231 * prefix contains an invalid character.
232 * @exception DOMException
233 * @since WD-DOM-Level-2-19990923
234 */
235 public void setPrefix(String prefix)
236 throws DOMException
237 {
238 if (needsSyncData()) {
239 synchronizeData();
240 }
241 if (ownerDocument().errorChecking) {
242 if (isReadOnly()) {
243 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
244 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
245 }
246 if (prefix != null && prefix.length() != 0) {
247
248 if (!CoreDocumentImpl.isXMLName(prefix,ownerDocument().isXML11Version())) {
249 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
250 throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
251 }
252 if (namespaceURI == null || prefix.indexOf(':') >=0) {
253 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null);
254 throw new DOMException(DOMException.NAMESPACE_ERR, msg);
255
256 }
257 if (prefix.equals("xmlns")) {
258 if (!namespaceURI.equals(xmlnsURI)){
259 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null);
260 throw new DOMException(DOMException.NAMESPACE_ERR, msg);
261 }
262 } else if (prefix.equals("xml")) {
263 if (!namespaceURI.equals(xmlURI)) {
264 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null);
265 throw new DOMException(DOMException.NAMESPACE_ERR, msg);
266 }
267 }else if (name.equals("xmlns")) {
268 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null);
269 throw new DOMException(DOMException.NAMESPACE_ERR, msg);
270 }
271 }
272 }
273
274 // update node name with new qualifiedName
275 if (prefix !=null && prefix.length() != 0) {
276 name = prefix + ":" + localName;
277 }
278 else {
279 name = localName;
280 }
281 }
282
283 /**
284 * Introduced in DOM Level 2. <p>
285 *
286 * Returns the local part of the qualified name of this node.
287 * @since WD-DOM-Level-2-19990923
288 */
289 public String getLocalName()
290 {
291 if (needsSyncData()) {
292 synchronizeData();
293 }
294 return localName;
295 }
296
297
298 /**
299 * @see org.w3c.dom.TypeInfo#getTypeName()
300 */
301 public String getTypeName() {
302 if (type !=null){
303 if (type instanceof XSSimpleTypeDecl){
304 return ((XSSimpleTypeDecl)type).getName();
305 }
306 return (String)type;
307 }
308 return null;
309 }
310
311 /**
312 * Introduced in DOM Level 3. <p>
313 * Checks if a type is derived from another by restriction. See:
314 * http://www.w3.org/TR/DOM-Level-3-Core/core.html#TypeInfo-isDerivedFrom
315 *
316 * @param ancestorNS
317 * The namspace of the ancestor type declaration
318 * @param ancestorName
319 * The name of the ancestor type declaration
320 * @param type
321 * The reference type definition
322 *
323 * @return boolean True if the type is derived by restriciton for the
324 * reference type
325 */
326 public boolean isDerivedFrom(String typeNamespaceArg,
327 String typeNameArg,
328 int derivationMethod) {
329 if (type != null) {
330 if (type instanceof XSSimpleTypeDefinition) {
331 return ((XSSimpleTypeDecl) type).isDOMDerivedFrom(
332 typeNamespaceArg, typeNameArg, derivationMethod);
333 }
334 }
335 return false;
336 }
337
338 /**
339 * @see org.w3c.dom.TypeInfo#getTypeNamespace()
340 */
341 public String getTypeNamespace() {
342 if (type !=null) {
343 if (type instanceof XSSimpleTypeDecl){
344 return ((XSSimpleTypeDecl)type).getNamespace();
345 }
346 return DTD_URI;
347 }
348 return null;
349 }
350
351 }