1 /* Copyright 2005 Elliotte Rusty Harold
2 
3    This library is free software; you can redistribute it and/or modify
4    it under the terms of version 2.1 of the GNU Lesser General Public
5    License as published by the Free Software Foundation.
6 
7    This library is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10    GNU Lesser General Public License for more details.
11 
12    You should have received a copy of the GNU Lesser General Public
13    License along with this library; if not, write to the
14    Free Software Foundation, Inc., 59 Temple Place, Suite 330,
15    Boston, MA 02111-1307  USA
16 
17    You can contact Elliotte Rusty Harold by sending e-mail to
18    elharo@ibiblio.org. Please include the word "XOM" in the
19    subject line. The XOM home page is located at http://www.xom.nu/
20 */
21 
22 package nu.xom;
23 
24 /**
25  * <p>
26  * Represents a namespace in scope. It is used by XOM's
27  * XPath implementation for the namespace axis. However, it is not
28  * really part of the XOM data model. Namespace objects are only
29  * created as needed when evaluating XPath. While a namespace node has
30  * a parent element (which may be null), that element does not know
31  * about these namespace nodes and cannot remove them. (This is an
32  * inconsistency in the XPath data model, and is shared with attributes
33  * which also have parents but are not children.)
34  * </p>
35  *
36  * @author Elliotte Rusty Harold
37  * @version 1.1b3
38  *
39  */
40 public final class Namespace extends Node {
41 
42     private final String prefix;
43     private final String uri;
44 
45     /**
46      * Namespace URI specified for <code>xml</code> prefix
47      */
48     public final static String XML_NAMESPACE
49       = "http://www.w3.org/XML/1998/namespace";
50 
51 
52     /**
53      * <p>
54      * Create a new namespace node.
55      * </p>
56      *
57      * @param prefix the prefix for the namespace; may be the empty
58      *     string or a non-colonized name
59      * @param URI the namespace URI
60      * @param parent the element that possesses this namespace node
61      *
62      * @throws MalformedURIException if <code>URI</code> is
63      *     not an RFC 3986 URI reference
64      * @throws IllegalNameException if
65      *  <ul>
66      *      <li>The prefix is <code>xmlns</code>.</li>
67      *      <li>The prefix is not the empty string, and the URI is
68      *          null or the empty string.</li>
69      * </ul>
70      * @throws NamespaceConflictException if
71      *  <ul>
72      *      <li>The prefix is the empty string, and the URI is
73      *          null or the empty string.</li>
74      *      <li>The prefix is <code>xml</code>, and the URI is not
75      *          <code>http://www.w3.org/XML/1998/namespace</code>.</li>
76      *      <li>The prefix is not <code>xml</code>, and the URI is
77      *          <code>http://www.w3.org/XML/1998/namespace</code>.</li>
78      * </ul>
79      */
Namespace(String prefix, String URI, Element parent)80     public Namespace(String prefix, String URI, Element parent) {
81 
82         if (prefix == null) prefix = "";
83         else if ("xmlns".equals(prefix)) {
84             throw new IllegalNameException(
85               "The xmlns prefix may not be bound to a URI.");
86         }
87         else if ("xml".equals(prefix)) {
88             if (! XML_NAMESPACE.equals(URI) ) {
89                 throw new NamespaceConflictException(
90                   "The prefix xml can only be bound to the URI "
91                   + "http://www.w3.org/XML/1998/namespace");
92             }
93         }
94 
95         if (prefix.length() != 0) Verifier.checkNCName(prefix);
96 
97         if (URI == null) URI = "";
98         else if (URI.equals(XML_NAMESPACE)) {
99             if (! "xml".equals(prefix)) {
100                 throw new NamespaceConflictException(
101                   "The URI http://www.w3.org/XML/1998/namespace can "
102                   + "only be bound to the prefix xml");
103             }
104         }
105 
106         if (URI.length() == 0) { // faster than "".equals(uri)
107             if (prefix.length() != 0) {
108                 throw new NamespaceConflictException(
109                  "Prefixed elements must have namespace URIs."
110                 );
111             }
112         }
113         else Verifier.checkAbsoluteURIReference(URI);
114 
115         this.prefix = prefix;
116         this.uri = URI;
117         super.setParent(parent);
118     }
119 
120 
121     /**
122      * <p>
123      * Returns the namespace prefix, or the empty string if this node
124      * is the default namespace.
125      * </p>
126      *
127      * @return the namespace prefix
128      */
getPrefix()129     public String getPrefix() {
130         return prefix;
131     }
132 
133 
134     /**
135      * <p>
136      * Returns the namespace URI.
137      * </p>
138      *
139      * @return the namespace URI
140      */
getValue()141     public String getValue() {
142         return uri;
143     }
144 
145 
146      /**
147      * <p>
148      * Throws <code>IndexOutOfBoundsException</code> because
149      * namespaces do not have children.
150      * </p>
151      *
152      * @return never returns because document type declarations do not
153      *     have children. Always throws an exception.
154      *
155      * @param position the index of the child node to return
156      *
157      * @throws IndexOutOfBoundsException because document type declarations
158      *     do not have children
159      */
getChild(int position)160     public Node getChild(int position) {
161         throw new IndexOutOfBoundsException(
162           "Namespaces do not have children");
163     }
164 
165 
166     /**
167      * <p>
168      * Returns 0 because namespaces do not have
169      * children.
170      * </p>
171      *
172      * @return zero
173      */
getChildCount()174     public int getChildCount() {
175         return 0;
176     }
177 
178 
179     /**
180      * <p>
181      *   Returns a copy of this namespace which has
182      *   the same prefix and URI, but no parent.
183      * </p>
184      *
185      * @return a copy of this <code>Namespace</code>
186      *     that is not part of a document
187      */
copy()188     public Node copy() {
189         return new Namespace(prefix, uri, null);
190     }
191 
192 
193     /**
194      * <p>
195      * Removes this namespace node from its parent.
196      * </p>
197      *
198      * @see nu.xom.Node#detach()
199      */
detach()200     public void detach() {
201         super.setParent(null);
202     }
203 
204 
205     /**
206      * <p>
207      *  Returns a string containing the actual XML
208      *  form of the namespace declaration represented
209      *  by this object. For example,
210      *  <code>xmlns:pre="http://www.example.org/"</code>.
211      * </p>
212      *
213      * @return a <code>String</code> containing
214      *      an XML namespace declaration
215      */
toXML()216     public String toXML() {
217         String colon = prefix.equals("") ? "" : ":";
218         return "xmlns" + colon + prefix + "=\"" + uri + "\"";
219     }
220 
221 
222     /**
223      * <p>
224      * Returns a string form of the
225      * <code>Namespace</code> suitable for debugging
226      * and diagnosis. It deliberately does not return
227      * an actual XML namespace declaration.
228      * </p>
229      *
230      * @return a string representation of this object
231      */
toString()232     public String toString() {
233         return "[Namespace: " + this.toXML() + "]";
234     }
235 
236 
237 }