/*-- $Id: Namespace.java,v 1.20 2001/03/15 06:07:17 jhunter Exp $ Copyright (C) 2000 Brett McLaughlin & Jason Hunter. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the disclaimer that follows these conditions in the documentation and/or other materials provided with the distribution. 3. The name "JDOM" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact license@jdom.org. 4. Products derived from this software may not be called "JDOM", nor may "JDOM" appear in their name, without prior written permission from the JDOM Project Management (pm@jdom.org). In addition, we request (but do not require) that you include in the end-user documentation provided with the redistribution and/or in the software itself an acknowledgement equivalent to the following: "This product includes software developed by the JDOM Project (http://www.jdom.org/)." Alternatively, the acknowledgment may be graphical using the logos available at http://www.jdom.org/images/logos. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the JDOM Project and was originally created by Brett McLaughlin and Jason Hunter . For more information on the JDOM Project, please see . */ package org.jdom; import java.util.HashMap; import java.util.Iterator; import java.util.List; /** *

Namespace defines both a factory for * creating XML namespaces, and a namespace itself. This class * represents an XML namespace in Java. *

*

* Elements and Attributes containing Namespaces can be serialized; * however the Namespace class itself does not implement * java.io.Serializable. This works because the Element and * Attribute classes handle serialization of their Namespaces manually. * The classes use the getNamespace() method on deserialization to ensure * there may be only one unique Namespace object for any unique * prefix/uri pair, something needed for efficiency reasons. *

* * @author Brett McLaughlin * @author Elliotte Rusty Harold * @author Wesley Biggs * @version 1.0 */ public final class Namespace { // XXX May want to use weak references to keep the maps from growing // large with extended use /** * Factory list of namespaces. * Keys are prefix&URI. * Values are Namespace objects */ private static HashMap namespaces; /** Factory list of mappings */ private static HashMap mappings; /** Define a Namespace for when not in a namespace */ public static final Namespace NO_NAMESPACE = new Namespace("", ""); /** Define a Namespace for when in an empty namespace */ public static final Namespace EMPTY_NAMESPACE = new Namespace(null, null); public static final Namespace XML_NAMESPACE = new Namespace("xml", "http://www.w3.org/XML/1998/namespace"); /** The prefix mapped to this namespace */ private String prefix; /** The URI for this namespace */ private String uri; /** *

* This static initializer acts as a factory contructor. * It sets up storage and required initial values. *

* * XXX: Maybe this should be a singleton? The code would be cleaner (brett) */ static { namespaces = new HashMap(); mappings = new HashMap(); // Add the "empty" namespace namespaces.put("", NO_NAMESPACE); namespaces.put("", EMPTY_NAMESPACE); mappings.put("", ""); mappings.put("xml", "http://www.w3.org/XML/1998/namespace"); namespaces.put("xml&http://www.w3.org/XML/1998/namespace", XML_NAMESPACE); } /** *

* This will retrieve (if in existence) or create (if not) a * Namespace for the supplied prefix and URI. *

* * @param prefix String prefix to map to * Namespace. * @param uri String URI of new Namespace. * @return Namespace - ready to use namespace. */ public static Namespace getNamespace(String prefix, String uri) { // Sanity checking if ((prefix == null) || (prefix.trim().equals(""))) { prefix = ""; } if ((uri == null) || (uri.trim().equals(""))) { uri = ""; } // Handle XML namespace if (prefix.equals("xml")) { return XML_NAMESPACE; } // Return existing namespace if found Namespace preexisting = (Namespace) namespaces.get(prefix + "&" + uri); if (preexisting != null) { return preexisting; } // Ensure proper naming String reason; if ((reason = Verifier.checkNamespacePrefix(prefix)) != null) { throw new IllegalNameException(prefix, "Namespace prefix", reason); } if ((reason = Verifier.checkNamespaceURI(uri)) != null) { throw new IllegalNameException(uri, "Namespace URI", reason); } // Unless the "empty" Namespace (no prefix and no URI), require a URI if ((!prefix.equals("")) && (uri.equals(""))) { throw new IllegalNameException("", "namespace", "Namespace URIs must be non-null and non-empty Strings."); } // Finally, store and return mappings.put(prefix, uri); Namespace ns = new Namespace(prefix, uri); namespaces.put(prefix + "&" + uri, ns); return ns; } /** *

* This will retrieve (if in existence) or create (if not) a * Namespace for the supplied URI, and make it usable * as a default namespace, as no prefix is supplied. *

* * @param uri String URI of new Namespace. * @return Namespace - ready to use namespace. */ public static Namespace getNamespace(String uri) { return getNamespace("", uri); } /** *

* This will retrieve the * Namespace for the supplied prefix * in the specified context. It returns null if the prefix * is not mapped within that element. *

* * @param prefix String prefix of the existing Namespace. * @param context Element against which this prefix is resolved. * @return Namespace - ready to use namespace. * * @deprecated Deprecated in beta6, use elt.getNamespace(prefix) instead */ public static Namespace getNamespace(String prefix, Element context) { if (context == null) { return null; } Namespace ns = context.getNamespace(); if (ns.getPrefix().equals(prefix)) { return ns; } // check the Attributes for the requested prefix List attributes = context.getAttributes(); Iterator iterator = attributes.iterator(); while (iterator.hasNext()) { Attribute a = (Attribute) iterator.next(); ns = a.getNamespace(); if (ns.getPrefix().equals(prefix)) { return ns; } } // recurse through the ancestors return getNamespace(prefix, context.getParent()); } /** *

* This constructor handles creation of a Namespace object * with a prefix and URI; it is intentionally left private * so that it cannot be invoked by external programs/code. *

* * @param prefix String prefix to map to this namespace. * @param uri String URI for namespace. */ private Namespace(String prefix, String uri) { this.prefix = prefix; this.uri = uri; } /** *

* This returns the prefix mapped to this Namespace. *

* * @return String - prefix for this Namespace. */ public String getPrefix() { return prefix == null? "" : prefix; } /** *

* This returns the namespace URI for this Namespace. *

* * @return String - URI for this Namespace. */ public String getURI() { return uri == null? "" : uri; } /** *

* This tests for equality - Two Namespaces * are equal if and only if their URIs are byte-for-byte equals * and their prefixes are equal. *

* * @param ob Object to compare to this Namespace. * @return boolean - whether the supplied object is equal to * this Namespace. */ public boolean equals(Object ob) { if (ob == null) { return false; } if (ob instanceof Namespace) { Namespace ns = (Namespace)ob; //special case for empty namspace if (ns == Namespace.EMPTY_NAMESPACE || uri == null) return ns == this; // Compare URIs if (ns.getURI().equals(uri) && ns.getPrefix().equals(prefix)) { return true; } } return false; } /** *

* This returns a String representation of this * Namespace, suitable for use in debugging. *

* * @return String - information about this instance. */ public String toString() { return "[Namespace: prefix \"" + prefix + "\" is mapped to URI \"" + uri + "\"]"; } /** *

* This returns a probably unique hash code for the Namespace. * If two namespaces have the same URI, they are equal and have the same * hash code, even if they have different prefixes. *

* * @return int - hash code for this Namespace. */ public int hashCode() { // Since neither URI nor prefix are guaranteed to be unique, // use the combination return (prefix+uri).hashCode(); } }