View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 1999-2002,2004,2005 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.xs.XSSimpleTypeDefinition;
24  import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
25  import com.sun.org.apache.xerces.internal.impl.dv.xs.XSSimpleTypeDecl;
26  import com.sun.org.apache.xerces.internal.impl.xs.XSComplexTypeDecl;
27  import com.sun.org.apache.xerces.internal.util.URI;
28  import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
29  import org.w3c.dom.Attr;
30  import org.w3c.dom.DOMException;
31  
32  
33  
34  /**
35   * ElementNSImpl inherits from ElementImpl and adds namespace support.
36   * <P>
37   * The qualified name is the node name, and we store localName which is also
38   * used in all queries. On the other hand we recompute the prefix when
39   * necessary.
40   *
41   * @xerces.internal
42   *
43   * @author Elena litani, IBM
44   * @author Neeraj Bajaj, Sun Microsystems
45   * @version $Id: ElementNSImpl.java,v 1.7 2010-11-01 04:39:39 joehw Exp $
46   */
47  public class ElementNSImpl
48      extends ElementImpl {
49  
50      //
51      // Constants
52      //
53  
54      /** Serialization version. */
55      static final long serialVersionUID = -9142310625494392642L;
56      static final String xmlURI = "http://www.w3.org/XML/1998/namespace";
57  
58      //
59      // Data
60      //
61  
62      /** DOM2: Namespace URI. */
63      protected String namespaceURI;
64  
65      /** DOM2: localName. */
66      protected String localName;
67  
68      /** DOM3: type information */
69      // REVISIT: we are losing the type information in DOM during serialization
70      transient XSTypeDefinition type;
71  
72      protected ElementNSImpl() {
73          super();
74      }
75      /**
76       * DOM2: Constructor for Namespace implementation.
77       */
78      protected ElementNSImpl(CoreDocumentImpl ownerDocument,
79                              String namespaceURI,
80                              String qualifiedName)
81          throws DOMException
82      {
83          super(ownerDocument, qualifiedName);
84          setName(namespaceURI, qualifiedName);
85      }
86  
87          private void setName(String namespaceURI, String qname) {
88  
89                  String prefix;
90                  // DOM Level 3: namespace URI is never empty string.
91                  this.namespaceURI = namespaceURI;
92                  if (namespaceURI != null) {
93              //convert the empty string to 'null'
94                          this.namespaceURI =     (namespaceURI.length() == 0) ? null : namespaceURI;
95                  }
96  
97          int colon1, colon2 ;
98  
99          //NAMESPACE_ERR:
100         //1. if the qualified name is 'null' it is malformed.
101         //2. or if the qualifiedName is null and the namespaceURI is different from null,
102         // We dont need to check for namespaceURI != null, if qualified name is null throw DOMException.
103         if(qname == null){
104                                 String msg =
105                                         DOMMessageFormatter.formatMessage(
106                                                 DOMMessageFormatter.DOM_DOMAIN,
107                                                 "NAMESPACE_ERR",
108                                                 null);
109                                 throw new DOMException(DOMException.NAMESPACE_ERR, msg);
110         }
111         else{
112                     colon1 = qname.indexOf(':');
113                     colon2 = qname.lastIndexOf(':');
114         }
115 
116                 ownerDocument.checkNamespaceWF(qname, colon1, colon2);
117                 if (colon1 < 0) {
118                         // there is no prefix
119                         localName = qname;
120                         if (ownerDocument.errorChecking) {
121                             ownerDocument.checkQName(null, localName);
122                             if (qname.equals("xmlns")
123                                 && (namespaceURI == null
124                                 || !namespaceURI.equals(NamespaceContext.XMLNS_URI))
125                                 || (namespaceURI!=null && namespaceURI.equals(NamespaceContext.XMLNS_URI)
126                                 && !qname.equals("xmlns"))) {
127                                 String msg =
128                                     DOMMessageFormatter.formatMessage(
129                                             DOMMessageFormatter.DOM_DOMAIN,
130                                             "NAMESPACE_ERR",
131                                             null);
132                                 throw new DOMException(DOMException.NAMESPACE_ERR, msg);
133                             }
134                         }
135                 }//there is a prefix
136                 else {
137                     prefix = qname.substring(0, colon1);
138                     localName = qname.substring(colon2 + 1);
139 
140                     //NAMESPACE_ERR:
141                     //1. if the qualifiedName has a prefix and the namespaceURI is null,
142 
143                     //2. or if the qualifiedName has a prefix that is "xml" and the namespaceURI
144                     //is different from " http://www.w3.org/XML/1998/namespace"
145 
146                     if (ownerDocument.errorChecking) {
147                         if( namespaceURI == null || ( prefix.equals("xml") && !namespaceURI.equals(NamespaceContext.XML_URI) )){
148                             String msg =
149                                 DOMMessageFormatter.formatMessage(
150                                         DOMMessageFormatter.DOM_DOMAIN,
151                                         "NAMESPACE_ERR",
152                                         null);
153                             throw new DOMException(DOMException.NAMESPACE_ERR, msg);
154                         }
155 
156                         ownerDocument.checkQName(prefix, localName);
157                         ownerDocument.checkDOMNSErr(prefix, namespaceURI);
158                     }
159                 }
160         }
161 
162     // when local name is known
163     protected ElementNSImpl(CoreDocumentImpl ownerDocument,
164                             String namespaceURI, String qualifiedName,
165                             String localName)
166         throws DOMException
167     {
168         super(ownerDocument, qualifiedName);
169 
170         this.localName = localName;
171         this.namespaceURI = namespaceURI;
172     }
173 
174     // for DeferredElementImpl
175     protected ElementNSImpl(CoreDocumentImpl ownerDocument,
176                             String value) {
177         super(ownerDocument, value);
178     }
179 
180     // Support for DOM Level 3 renameNode method.
181     // Note: This only deals with part of the pb. CoreDocumentImpl
182     // does all the work.
183     void rename(String namespaceURI, String qualifiedName)
184     {
185         if (needsSyncData()) {
186             synchronizeData();
187         }
188                 this.name = qualifiedName;
189         setName(namespaceURI, qualifiedName);
190         reconcileDefaultAttributes();
191     }
192 
193     /**
194      * NON-DOM: resets this node and sets specified values for the node
195      *
196      * @param ownerDocument
197      * @param namespaceURI
198      * @param qualifiedName
199      * @param localName
200      */
201     protected void setValues (CoreDocumentImpl ownerDocument,
202                             String namespaceURI, String qualifiedName,
203                             String localName){
204 
205         // remove children first
206         firstChild = null;
207         previousSibling = null;
208         nextSibling = null;
209         fNodeListCache = null;
210 
211         // set owner document
212         attributes = null;
213         super.flags = 0;
214         setOwnerDocument(ownerDocument);
215 
216         // synchronizeData will initialize attributes
217         needsSyncData(true);
218         super.name = qualifiedName;
219         this.localName = localName;
220         this.namespaceURI = namespaceURI;
221 
222     }
223 
224     //
225     // Node methods
226     //
227 
228 
229 
230     //
231     //DOM2: Namespace methods.
232     //
233 
234     /**
235      * Introduced in DOM Level 2. <p>
236      *
237      * The namespace URI of this node, or null if it is unspecified.<p>
238      *
239      * This is not a computed value that is the result of a namespace lookup based on
240      * an examination of the namespace declarations in scope. It is merely the
241      * namespace URI given at creation time.<p>
242      *
243      * For nodes created with a DOM Level 1 method, such as createElement
244      * from the Document interface, this is null.
245      * @since WD-DOM-Level-2-19990923
246      */
247     public String getNamespaceURI()
248     {
249         if (needsSyncData()) {
250             synchronizeData();
251         }
252         return namespaceURI;
253     }
254 
255     /**
256      * Introduced in DOM Level 2. <p>
257      *
258      * The namespace prefix of this node, or null if it is unspecified. <p>
259      *
260      * For nodes created with a DOM Level 1 method, such as createElement
261      * from the Document interface, this is null. <p>
262      *
263      * @since WD-DOM-Level-2-19990923
264      */
265     public String getPrefix()
266     {
267 
268         if (needsSyncData()) {
269             synchronizeData();
270         }
271         int index = name.indexOf(':');
272         return index < 0 ? null : name.substring(0, index);
273     }
274 
275     /**
276      * Introduced in DOM Level 2. <p>
277      *
278      * Note that setting this attribute changes the nodeName attribute, which holds the
279      * qualified name, as well as the tagName and name attributes of the Element
280      * and Attr interfaces, when applicable.<p>
281      *
282      * @param prefix The namespace prefix of this node, or null(empty string) if it is unspecified.
283      *
284      * @exception INVALID_CHARACTER_ERR
285      *                   Raised if the specified
286      *                   prefix contains an invalid character.
287      * @exception DOMException
288      * @since WD-DOM-Level-2-19990923
289      */
290     public void setPrefix(String prefix)
291         throws DOMException
292     {
293         if (needsSyncData()) {
294             synchronizeData();
295         }
296         if (ownerDocument.errorChecking) {
297             if (isReadOnly()) {
298                 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
299                 throw new DOMException(
300                                      DOMException.NO_MODIFICATION_ALLOWED_ERR,
301                                      msg);
302             }
303             if (prefix != null && prefix.length() != 0) {
304                 if (!CoreDocumentImpl.isXMLName(prefix,ownerDocument.isXML11Version())) {
305                     String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
306                     throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
307                 }
308                 if (namespaceURI == null || prefix.indexOf(':') >=0) {
309                     String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null);
310                     throw new DOMException(DOMException.NAMESPACE_ERR, msg);
311                 } else if (prefix.equals("xml")) {
312                      if (!namespaceURI.equals(xmlURI)) {
313                          String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null);
314                          throw new DOMException(DOMException.NAMESPACE_ERR, msg);
315                      }
316                 }
317             }
318 
319         }
320         // update node name with new qualifiedName
321         if (prefix !=null && prefix.length() != 0) {
322             name = prefix + ":" + localName;
323         }
324         else {
325             name = localName;
326         }
327     }
328 
329     /**
330      * Introduced in DOM Level 2. <p>
331      *
332      * Returns the local part of the qualified name of this node.
333      * @since WD-DOM-Level-2-19990923
334      */
335     public String getLocalName()
336     {
337         if (needsSyncData()) {
338             synchronizeData();
339         }
340         return localName;
341     }
342 
343 
344    /**
345      * DOM Level 3 WD - Experimental.
346      * Retrieve baseURI
347      */
348     public String getBaseURI() {
349 
350         if (needsSyncData()) {
351             synchronizeData();
352         }
353         // Absolute base URI is computed according to XML Base (http://www.w3.org/TR/xmlbase/#granularity)
354 
355         // 1.  the base URI specified by an xml:base attribute on the element, if one exists
356 
357         if (attributes != null) {
358             Attr attrNode = (Attr)attributes.getNamedItemNS("http://www.w3.org/XML/1998/namespace", "base");
359             if (attrNode != null) {
360                 String uri =  attrNode.getNodeValue();
361                 if (uri.length() != 0 ) {// attribute value is always empty string
362                     try {
363                         uri = new URI(uri).toString();
364                     }
365                     catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException e) {
366                         // This may be a relative URI.
367 
368                         // Start from the base URI of the parent, or if this node has no parent, the owner node.
369                         NodeImpl parentOrOwner = (parentNode() != null) ? parentNode() : ownerNode;
370 
371                         // Make any parentURI into a URI object to use with the URI(URI, String) constructor.
372                         String parentBaseURI = (parentOrOwner != null) ? parentOrOwner.getBaseURI() : null;
373 
374                         if (parentBaseURI != null) {
375                             try {
376                                 uri = new URI(new URI(parentBaseURI), uri).toString();
377                             }
378                             catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException ex){
379                                 // This should never happen: parent should have checked the URI and returned null if invalid.
380                                 return null;
381                             }
382                             return uri;
383                         }
384                         // REVISIT: what should happen in this case?
385                         return null;
386                     }
387                     return uri;
388                 }
389             }
390         }
391 
392         //2.the base URI of the element's parent element within the document or external entity,
393         //if one exists
394         String parentElementBaseURI = (this.parentNode() != null) ? this.parentNode().getBaseURI() : null ;
395         //base URI of parent element is not null
396         if(parentElementBaseURI != null){
397             try {
398                 //return valid absolute base URI
399                return new URI(parentElementBaseURI).toString();
400             }
401             catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException e){
402                 // REVISIT: what should happen in this case?
403                 return null;
404             }
405         }
406         //3. the base URI of the document entity or external entity containing the element
407 
408         String baseURI = (this.ownerNode != null) ? this.ownerNode.getBaseURI() : null ;
409 
410         if(baseURI != null){
411             try {
412                 //return valid absolute base URI
413                return new URI(baseURI).toString();
414             }
415             catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException e){
416                 // REVISIT: what should happen in this case?
417                 return null;
418             }
419         }
420 
421         return null;
422 
423     }
424 
425 
426     /**
427      * @see org.w3c.dom.TypeInfo#getTypeName()
428      */
429     public String getTypeName() {
430         if (type !=null){
431             if (type instanceof XSSimpleTypeDecl) {
432                 return ((XSSimpleTypeDecl) type).getTypeName();
433             } else if (type instanceof XSComplexTypeDecl) {
434                 return ((XSComplexTypeDecl) type).getTypeName();
435             }
436         }
437         return null;
438     }
439 
440     /**
441      * @see org.w3c.dom.TypeInfo#getTypeNamespace()
442      */
443     public String getTypeNamespace() {
444         if (type !=null){
445             return type.getNamespace();
446         }
447         return null;
448     }
449 
450     /**
451      * Introduced in DOM Level 2. <p>
452      * Checks if a type is derived from another by restriction. See:
453      * http://www.w3.org/TR/DOM-Level-3-Core/core.html#TypeInfo-isDerivedFrom
454      *
455      * @param ancestorNS
456      *        The namspace of the ancestor type declaration
457      * @param ancestorName
458      *        The name of the ancestor type declaration
459      * @param type
460      *        The reference type definition
461      *
462      * @return boolean True if the type is derived by restriciton for the
463      *         reference type
464      */
465     public boolean isDerivedFrom(String typeNamespaceArg, String typeNameArg,
466             int derivationMethod) {
467         if(needsSyncData()) {
468             synchronizeData();
469         }
470         if (type != null) {
471             if (type instanceof XSSimpleTypeDecl) {
472                 return ((XSSimpleTypeDecl) type).isDOMDerivedFrom(
473                         typeNamespaceArg, typeNameArg, derivationMethod);
474             } else if (type instanceof XSComplexTypeDecl) {
475                 return ((XSComplexTypeDecl) type).isDOMDerivedFrom(
476                         typeNamespaceArg, typeNameArg, derivationMethod);
477             }
478         }
479         return false;
480     }
481 
482     /**
483      * NON-DOM: setting type used by the DOM parser
484      * @see NodeImpl#setReadOnly
485      */
486     public void setType(XSTypeDefinition type) {
487         this.type = type;
488     }
489 }