001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xerces.dom;
019:
020: import org.apache.xerces.xs.XSSimpleTypeDefinition;
021: import org.apache.xerces.xs.XSTypeDefinition;
022: import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl;
023: import org.apache.xerces.impl.xs.XSComplexTypeDecl;
024: import org.apache.xerces.util.URI;
025: import org.apache.xerces.xni.NamespaceContext;
026: import org.w3c.dom.Attr;
027: import org.w3c.dom.DOMException;
028:
029: /**
030: * ElementNSImpl inherits from ElementImpl and adds namespace support.
031: * <P>
032: * The qualified name is the node name, and we store localName which is also
033: * used in all queries. On the other hand we recompute the prefix when
034: * necessary.
035: *
036: * @xerces.internal
037: *
038: * @author Elena litani, IBM
039: * @author Neeraj Bajaj, Sun Microsystems
040: * @version $Id: ElementNSImpl.java 449328 2006-09-23 22:58:23Z mrglavas $
041: */
042: public class ElementNSImpl extends ElementImpl {
043:
044: //
045: // Constants
046: //
047:
048: /** Serialization version. */
049: static final long serialVersionUID = -9142310625494392642L;
050: static final String xmlURI = "http://www.w3.org/XML/1998/namespace";
051:
052: //
053: // Data
054: //
055:
056: /** DOM2: Namespace URI. */
057: protected String namespaceURI;
058:
059: /** DOM2: localName. */
060: protected String localName;
061:
062: /** DOM3: type information */
063: // REVISIT: we are losing the type information in DOM during serialization
064: transient XSTypeDefinition type;
065:
066: protected ElementNSImpl() {
067: super ();
068: }
069:
070: /**
071: * DOM2: Constructor for Namespace implementation.
072: */
073: protected ElementNSImpl(CoreDocumentImpl ownerDocument,
074: String namespaceURI, String qualifiedName)
075: throws DOMException {
076: super (ownerDocument, qualifiedName);
077: setName(namespaceURI, qualifiedName);
078: }
079:
080: private void setName(String namespaceURI, String qname) {
081:
082: String prefix;
083: // DOM Level 3: namespace URI is never empty string.
084: this .namespaceURI = namespaceURI;
085: if (namespaceURI != null) {
086: //convert the empty string to 'null'
087: this .namespaceURI = (namespaceURI.length() == 0) ? null
088: : namespaceURI;
089: }
090:
091: int colon1, colon2;
092:
093: //NAMESPACE_ERR:
094: //1. if the qualified name is 'null' it is malformed.
095: //2. or if the qualifiedName is null and the namespaceURI is different from null,
096: // We dont need to check for namespaceURI != null, if qualified name is null throw DOMException.
097: if (qname == null) {
098: String msg = DOMMessageFormatter.formatMessage(
099: DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR",
100: null);
101: throw new DOMException(DOMException.NAMESPACE_ERR, msg);
102: } else {
103: colon1 = qname.indexOf(':');
104: colon2 = qname.lastIndexOf(':');
105: }
106:
107: ownerDocument.checkNamespaceWF(qname, colon1, colon2);
108: if (colon1 < 0) {
109: // there is no prefix
110: localName = qname;
111: if (ownerDocument.errorChecking) {
112: ownerDocument.checkQName(null, localName);
113: if (qname.equals("xmlns")
114: && (namespaceURI == null || !namespaceURI
115: .equals(NamespaceContext.XMLNS_URI))
116: || (namespaceURI != null
117: && namespaceURI
118: .equals(NamespaceContext.XMLNS_URI) && !qname
119: .equals("xmlns"))) {
120: String msg = DOMMessageFormatter.formatMessage(
121: DOMMessageFormatter.DOM_DOMAIN,
122: "NAMESPACE_ERR", null);
123: throw new DOMException(DOMException.NAMESPACE_ERR,
124: msg);
125: }
126: }
127: }//there is a prefix
128: else {
129: prefix = qname.substring(0, colon1);
130: localName = qname.substring(colon2 + 1);
131:
132: //NAMESPACE_ERR:
133: //1. if the qualifiedName has a prefix and the namespaceURI is null,
134:
135: //2. or if the qualifiedName has a prefix that is "xml" and the namespaceURI
136: //is different from " http://www.w3.org/XML/1998/namespace"
137:
138: if (ownerDocument.errorChecking) {
139: if (namespaceURI == null
140: || (prefix.equals("xml") && !namespaceURI
141: .equals(NamespaceContext.XML_URI))) {
142: String msg = DOMMessageFormatter.formatMessage(
143: DOMMessageFormatter.DOM_DOMAIN,
144: "NAMESPACE_ERR", null);
145: throw new DOMException(DOMException.NAMESPACE_ERR,
146: msg);
147: }
148:
149: ownerDocument.checkQName(prefix, localName);
150: ownerDocument.checkDOMNSErr(prefix, namespaceURI);
151: }
152: }
153: }
154:
155: // when local name is known
156: protected ElementNSImpl(CoreDocumentImpl ownerDocument,
157: String namespaceURI, String qualifiedName, String localName)
158: throws DOMException {
159: super (ownerDocument, qualifiedName);
160:
161: this .localName = localName;
162: this .namespaceURI = namespaceURI;
163: }
164:
165: // for DeferredElementImpl
166: protected ElementNSImpl(CoreDocumentImpl ownerDocument, String value) {
167: super (ownerDocument, value);
168: }
169:
170: // Support for DOM Level 3 renameNode method.
171: // Note: This only deals with part of the pb. CoreDocumentImpl
172: // does all the work.
173: void rename(String namespaceURI, String qualifiedName) {
174: if (needsSyncData()) {
175: synchronizeData();
176: }
177: this .name = qualifiedName;
178: setName(namespaceURI, qualifiedName);
179: reconcileDefaultAttributes();
180: }
181:
182: /**
183: * NON-DOM: resets this node and sets specified values for the node
184: *
185: * @param ownerDocument
186: * @param namespaceURI
187: * @param qualifiedName
188: * @param localName
189: */
190: protected void setValues(CoreDocumentImpl ownerDocument,
191: String namespaceURI, String qualifiedName, String localName) {
192:
193: // remove children first
194: firstChild = null;
195: previousSibling = null;
196: nextSibling = null;
197: fNodeListCache = null;
198:
199: // set owner document
200: attributes = null;
201: super .flags = 0;
202: setOwnerDocument(ownerDocument);
203:
204: // synchronizeData will initialize attributes
205: needsSyncData(true);
206: super .name = qualifiedName;
207: this .localName = localName;
208: this .namespaceURI = namespaceURI;
209:
210: }
211:
212: //
213: // Node methods
214: //
215:
216: //
217: //DOM2: Namespace methods.
218: //
219:
220: /**
221: * Introduced in DOM Level 2. <p>
222: *
223: * The namespace URI of this node, or null if it is unspecified.<p>
224: *
225: * This is not a computed value that is the result of a namespace lookup based on
226: * an examination of the namespace declarations in scope. It is merely the
227: * namespace URI given at creation time.<p>
228: *
229: * For nodes created with a DOM Level 1 method, such as createElement
230: * from the Document interface, this is null.
231: * @since WD-DOM-Level-2-19990923
232: */
233: public String getNamespaceURI() {
234: if (needsSyncData()) {
235: synchronizeData();
236: }
237: return namespaceURI;
238: }
239:
240: /**
241: * Introduced in DOM Level 2. <p>
242: *
243: * The namespace prefix of this node, or null if it is unspecified. <p>
244: *
245: * For nodes created with a DOM Level 1 method, such as createElement
246: * from the Document interface, this is null. <p>
247: *
248: * @since WD-DOM-Level-2-19990923
249: */
250: public String getPrefix() {
251:
252: if (needsSyncData()) {
253: synchronizeData();
254: }
255: int index = name.indexOf(':');
256: return index < 0 ? null : name.substring(0, index);
257: }
258:
259: /**
260: * Introduced in DOM Level 2. <p>
261: *
262: * Note that setting this attribute changes the nodeName attribute, which holds the
263: * qualified name, as well as the tagName and name attributes of the Element
264: * and Attr interfaces, when applicable.<p>
265: *
266: * @param prefix The namespace prefix of this node, or null(empty string) if it is unspecified.
267: *
268: * @exception INVALID_CHARACTER_ERR
269: * Raised if the specified
270: * prefix contains an invalid character.
271: * @exception DOMException
272: * @since WD-DOM-Level-2-19990923
273: */
274: public void setPrefix(String prefix) throws DOMException {
275: if (needsSyncData()) {
276: synchronizeData();
277: }
278: if (ownerDocument.errorChecking) {
279: if (isReadOnly()) {
280: String msg = DOMMessageFormatter.formatMessage(
281: DOMMessageFormatter.DOM_DOMAIN,
282: "NO_MODIFICATION_ALLOWED_ERR", null);
283: throw new DOMException(
284: DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
285: }
286: if (prefix != null && prefix.length() != 0) {
287: if (!CoreDocumentImpl.isXMLName(prefix, ownerDocument
288: .isXML11Version())) {
289: String msg = DOMMessageFormatter.formatMessage(
290: DOMMessageFormatter.DOM_DOMAIN,
291: "INVALID_CHARACTER_ERR", null);
292: throw new DOMException(
293: DOMException.INVALID_CHARACTER_ERR, msg);
294: }
295: if (namespaceURI == null || prefix.indexOf(':') >= 0) {
296: String msg = DOMMessageFormatter.formatMessage(
297: DOMMessageFormatter.DOM_DOMAIN,
298: "NAMESPACE_ERR", null);
299: throw new DOMException(DOMException.NAMESPACE_ERR,
300: msg);
301: } else if (prefix.equals("xml")) {
302: if (!namespaceURI.equals(xmlURI)) {
303: String msg = DOMMessageFormatter.formatMessage(
304: DOMMessageFormatter.DOM_DOMAIN,
305: "NAMESPACE_ERR", null);
306: throw new DOMException(
307: DOMException.NAMESPACE_ERR, msg);
308: }
309: }
310: }
311:
312: }
313: // update node name with new qualifiedName
314: if (prefix != null && prefix.length() != 0) {
315: name = prefix + ":" + localName;
316: } else {
317: name = localName;
318: }
319: }
320:
321: /**
322: * Introduced in DOM Level 2. <p>
323: *
324: * Returns the local part of the qualified name of this node.
325: * @since WD-DOM-Level-2-19990923
326: */
327: public String getLocalName() {
328: if (needsSyncData()) {
329: synchronizeData();
330: }
331: return localName;
332: }
333:
334: /**
335: * DOM Level 3 WD - Experimental.
336: * Retrieve baseURI
337: */
338: public String getBaseURI() {
339:
340: if (needsSyncData()) {
341: synchronizeData();
342: }
343: // Absolute base URI is computed according to XML Base (http://www.w3.org/TR/xmlbase/#granularity)
344:
345: // 1. the base URI specified by an xml:base attribute on the element, if one exists
346:
347: if (attributes != null) {
348: Attr attrNode = (Attr) attributes.getNamedItemNS(
349: "http://www.w3.org/XML/1998/namespace", "base");
350: if (attrNode != null) {
351: String uri = attrNode.getNodeValue();
352: if (uri.length() != 0) {// attribute value is always empty string
353: try {
354: uri = new URI(uri).toString();
355: } catch (org.apache.xerces.util.URI.MalformedURIException e) {
356: // This may be a relative URI.
357:
358: // Start from the base URI of the parent, or if this node has no parent, the owner node.
359: NodeImpl parentOrOwner = (parentNode() != null) ? parentNode()
360: : ownerNode;
361:
362: // Make any parentURI into a URI object to use with the URI(URI, String) constructor.
363: String parentBaseURI = (parentOrOwner != null) ? parentOrOwner
364: .getBaseURI()
365: : null;
366:
367: if (parentBaseURI != null) {
368: try {
369: uri = new URI(new URI(parentBaseURI),
370: uri).toString();
371: } catch (org.apache.xerces.util.URI.MalformedURIException ex) {
372: // This should never happen: parent should have checked the URI and returned null if invalid.
373: return null;
374: }
375: return uri;
376: }
377: // REVISIT: what should happen in this case?
378: return null;
379: }
380: return uri;
381: }
382: }
383: }
384:
385: //2.the base URI of the element's parent element within the document or external entity,
386: //if one exists
387: String parentElementBaseURI = (this .parentNode() != null) ? this
388: .parentNode().getBaseURI()
389: : null;
390: //base URI of parent element is not null
391: if (parentElementBaseURI != null) {
392: try {
393: //return valid absolute base URI
394: return new URI(parentElementBaseURI).toString();
395: } catch (org.apache.xerces.util.URI.MalformedURIException e) {
396: // REVISIT: what should happen in this case?
397: return null;
398: }
399: }
400: //3. the base URI of the document entity or external entity containing the element
401:
402: String baseURI = (this .ownerNode != null) ? this .ownerNode
403: .getBaseURI() : null;
404:
405: if (baseURI != null) {
406: try {
407: //return valid absolute base URI
408: return new URI(baseURI).toString();
409: } catch (org.apache.xerces.util.URI.MalformedURIException e) {
410: // REVISIT: what should happen in this case?
411: return null;
412: }
413: }
414:
415: return null;
416:
417: }
418:
419: /**
420: * @see org.w3c.dom.TypeInfo#getTypeName()
421: */
422: public String getTypeName() {
423: if (type != null) {
424: if (type instanceof XSSimpleTypeDefinition) {
425: return ((XSSimpleTypeDecl) type).getTypeName();
426: } else {
427: return ((XSComplexTypeDecl) type).getTypeName();
428: }
429: }
430: return null;
431: }
432:
433: /**
434: * @see org.w3c.dom.TypeInfo#getTypeNamespace()
435: */
436: public String getTypeNamespace() {
437: if (type != null) {
438: return type.getNamespace();
439: }
440: return null;
441: }
442:
443: /**
444: * Introduced in DOM Level 2. <p>
445: * Checks if a type is derived from another by restriction. See:
446: * http://www.w3.org/TR/DOM-Level-3-Core/core.html#TypeInfo-isDerivedFrom
447: *
448: * @param typeNamespaceArg
449: * The namspace of the ancestor type declaration
450: * @param typeNameArg
451: * The name of the ancestor type declaration
452: * @param derivationMethod
453: * The derivation method
454: *
455: * @return boolean True if the type is derived by restriciton for the
456: * reference type
457: */
458: public boolean isDerivedFrom(String typeNamespaceArg,
459: String typeNameArg, int derivationMethod) {
460: if (needsSyncData()) {
461: synchronizeData();
462: }
463: if (type != null) {
464: if (type instanceof XSSimpleTypeDefinition) {
465: return ((XSSimpleTypeDecl) type)
466: .isDOMDerivedFrom(typeNamespaceArg,
467: typeNameArg, derivationMethod);
468: } else {
469: return ((XSComplexTypeDecl) type)
470: .isDOMDerivedFrom(typeNamespaceArg,
471: typeNameArg, derivationMethod);
472: }
473: }
474: return false;
475: }
476:
477: /**
478: * NON-DOM: setting type used by the DOM parser
479: * @see NodeImpl#setReadOnly
480: */
481: public void setType(XSTypeDefinition type) {
482: this.type = type;
483: }
484: }
|