001 /*
002 * The Apache Software License, Version 1.1
003 *
004 *
005 * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
006 * reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions
010 * are met:
011 *
012 * 1. Redistributions of source code must retain the above copyright
013 * notice, this list of conditions and the following disclaimer.
014 *
015 * 2. Redistributions in binary form must reproduce the above copyright
016 * notice, this list of conditions and the following disclaimer in
017 * the documentation and/or other materials provided with the
018 * distribution.
019 *
020 * 3. The end-user documentation included with the redistribution,
021 * if any, must include the following acknowledgment:
022 * "This product includes software developed by the
023 * Apache Software Foundation ( http://www.apache.org/ )."
024 * Alternately, this acknowledgment may appear in the software itself,
025 * if and wherever such third-party acknowledgments normally appear.
026 *
027 * 4. The names "Axis" and "Apache Software Foundation" must
028 * not be used to endorse or promote products derived from this
029 * software without prior written permission. For written
030 * permission, please contact apache@apache.org .
031 *
032 * 5. Products derived from this software may not be called "Apache",
033 * nor may "Apache" appear in their name, without prior written
034 * permission of the Apache Software Foundation.
035 *
036 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047 * SUCH DAMAGE.
048 * ====================================================================
049 *
050 * This software consists of voluntary contributions made by many
051 * individuals on behalf of the Apache Software Foundation. For more
052 * information on the Apache Software Foundation, please see
053 * < http://www.apache.org/ >.
054 */
055 package groovy.xml;
056
057 import java.io.IOException;
058 import java.io.ObjectInputStream;
059 import java.io.Serializable;
060
061 /**
062 * <code>QName</code> class represents the value of a qualified name
063 * as specified in <a href=" http://www.w3.org/TR/xmlschema-2/#QName ">XML
064 * Schema Part2: Datatypes specification</a>.
065 * <p>
066 * The value of a QName contains a <b>namespaceURI</b>, a <b>localPart</b> and a <b>prefix</b>.
067 * The localPart provides the local part of the qualified name. The
068 * namespaceURI is a URI reference identifying the namespace.
069 *
070 * @version 1.1
071 */
072 public class QName implements Serializable {
073
074 /** comment/shared empty string */
075 private static final String emptyString = "".intern();
076
077 /** Field namespaceURI */
078 private String namespaceURI;
079
080 /** Field localPart */
081 private String localPart;
082
083 /** Field prefix */
084 private String prefix;
085
086 /**
087 * Constructor for the QName.
088 *
089 * @param localPart Local part of the QName
090 */
091 public QName(String localPart) {
092 this(emptyString, localPart, emptyString);
093 }
094
095 /**
096 * Constructor for the QName.
097 *
098 * @param namespaceURI Namespace URI for the QName
099 * @param localPart Local part of the QName.
100 */
101 public QName(String namespaceURI, String localPart) {
102 this(namespaceURI, localPart, emptyString);
103 }
104
105 /**
106 * Constructor for the QName.
107 *
108 * @param namespaceURI Namespace URI for the QName
109 * @param localPart Local part of the QName.
110 * @param prefix Prefix of the QName.
111 */
112 public QName(String namespaceURI, String localPart, String prefix) {
113 this.namespaceURI = (namespaceURI == null)
114 ? emptyString
115 : namespaceURI.intern();
116 if (localPart == null) {
117 throw new IllegalArgumentException("invalid QName local part");
118 } else {
119 this.localPart = localPart.intern();
120 }
121
122 if (prefix == null) {
123 throw new IllegalArgumentException("invalid QName prefix");
124 } else {
125 this.prefix = prefix.intern();
126 }
127 }
128
129 /**
130 * Gets the Namespace URI for this QName
131 *
132 * @return Namespace URI
133 */
134 public String getNamespaceURI() {
135 return namespaceURI;
136 }
137
138 /**
139 * Gets the Local part for this QName
140 *
141 * @return Local part
142 */
143 public String getLocalPart() {
144 return localPart;
145 }
146
147 /**
148 * Gets the Prefix for this QName
149 *
150 * @return Prefix
151 */
152 public String getPrefix() {
153 return prefix;
154 }
155
156 /**
157 * Returns the fully qualified name of this QName
158 *
159 * @return a string representation of the QName
160 */
161 public String getQualifiedName() {
162
163 return ((prefix.equals(emptyString))
164 ? localPart
165 : prefix + ':' + localPart);
166 }
167
168 /**
169 * Returns a string representation of this QName
170 *
171 * @return a string representation of the QName
172 */
173 public String toString() {
174
175 return ((namespaceURI.equals(emptyString))
176 ? localPart
177 : '{' + namespaceURI + '}' + localPart);
178 }
179
180 /**
181 * Tests this QName for equality with another object.
182 * <p>
183 * If the given object is not a QName or is null then this method
184 * returns <tt>false</tt>.
185 * <p>
186 * For two QNames to be considered equal requires that both
187 * localPart and namespaceURI must be equal. This method uses
188 * <code>String.equals</code> to check equality of localPart
189 * and namespaceURI. Any class that extends QName is required
190 * to satisfy this equality contract.
191 * <p>
192 * This method satisfies the general contract of the <code>Object.equals</code> method.
193 *
194 * @param obj the reference object with which to compare
195 *
196 * @return <code>true</code> if the given object is identical to this
197 * QName: <code>false</code> otherwise.
198 */
199 public final boolean equals(Object obj) {
200
201 if (obj == this) {
202 return true;
203 }
204
205 if (!(obj instanceof QName)) {
206 return false;
207 }
208
209 if ((namespaceURI.equals(((QName) obj).namespaceURI))
210 && (localPart == ((QName) obj).localPart)) {
211 return true;
212 }
213
214 return false;
215 }
216
217 /**
218 * Returns a QName holding the value of the specified String.
219 * <p>
220 * The string must be in the form returned by the QName.toString()
221 * method, i.e. "{namespaceURI}localPart", with the "{namespaceURI}"
222 * part being optional.
223 * <p>
224 * This method doesn't do a full validation of the resulting QName.
225 * In particular, it doesn't check that the resulting namespace URI
226 * is a legal URI (per RFC 2396 and RFC 2732), nor that the resulting
227 * local part is a legal NCName per the XML Namespaces specification.
228 *
229 * @param s the string to be parsed
230 * @throws java.lang.IllegalArgumentException If the specified String cannot be parsed as a QName
231 * @return QName corresponding to the given String
232 */
233 public static QName valueOf(String s) {
234
235 if ((s == null) || s.equals("")) {
236 throw new IllegalArgumentException("invalid QName literal");
237 }
238
239 if (s.charAt(0) == '{') {
240 int i = s.indexOf('}');
241
242 if (i == -1) {
243 throw new IllegalArgumentException("invalid QName literal");
244 }
245
246 if (i == s.length() - 1) {
247 throw new IllegalArgumentException("invalid QName literal");
248 } else {
249 return new QName(s.substring(1, i), s.substring(i + 1));
250 }
251 } else {
252 return new QName(s);
253 }
254 }
255
256 /**
257 * Returns a hash code value for this QName object. The hash code
258 * is based on both the localPart and namespaceURI parts of the
259 * QName. This method satisfies the general contract of the
260 * <code>Object.hashCode</code> method.
261 *
262 * @return a hash code value for this Qname object
263 */
264 public final int hashCode() {
265 return namespaceURI.hashCode() ^ localPart.hashCode();
266 }
267
268 /**
269 * Ensure that deserialization properly interns the results.
270 * @param in the ObjectInputStream to be read
271 */
272 private void readObject(ObjectInputStream in) throws
273 IOException, ClassNotFoundException {
274 in.defaultReadObject();
275
276 namespaceURI = namespaceURI.intern();
277 localPart = localPart.intern();
278 prefix = prefix.intern();
279 }
280 }