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