1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 package groovy.xml;
56
57 import java.io.IOException;
58 import java.io.ObjectInputStream;
59 import java.io.Serializable;
60
61 /***
62 * <code>QName</code> class represents the value of a qualified name
63 * as specified in <a href=" http://www.w3.org/TR/xmlschema-2/#QName ">XML
64 * Schema Part2: Datatypes specification</a>.
65 * <p>
66 * The value of a QName contains a <b>namespaceURI</b>, a <b>localPart</b> and a <b>prefix</b>.
67 * The localPart provides the local part of the qualified name. The
68 * namespaceURI is a URI reference identifying the namespace.
69 *
70 * @version 1.1
71 */
72 public class QName implements Serializable {
73
74 /*** comment/shared empty string */
75 private static final String emptyString = "".intern();
76
77 /*** Field namespaceURI */
78 private String namespaceURI;
79
80 /*** Field localPart */
81 private String localPart;
82
83 /*** Field prefix */
84 private String prefix;
85
86 /***
87 * Constructor for the QName.
88 *
89 * @param localPart Local part of the QName
90 */
91 public QName(String localPart) {
92 this(emptyString, localPart, emptyString);
93 }
94
95 /***
96 * Constructor for the QName.
97 *
98 * @param namespaceURI Namespace URI for the QName
99 * @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 == 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 == 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 == ((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 }