2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 // $Id: QName.java 754581 2009-03-15 01:32:39Z mrglavas $
20 package javax.xml.namespace;
22 import java.io.IOException;
23 import java.io.ObjectInputStream;
24 import java.io.Serializable;
25 import java.security.AccessController;
26 import java.security.PrivilegedAction;
27 import javax.xml.XMLConstants;
30 * <p><code>QName</code> represents a <strong>qualified name</strong>
31 * as defined in the XML specifications: <a
32 * href="http://www.w3.org/TR/xmlschema-2/#QName">XML Schema Part2:
33 * Datatypes specification</a>, <a
34 * href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces
36 * href="http://www.w3.org/XML/xml-names-19990114-errata">Namespaces
37 * in XML Errata</a>.</p>
39 * <p>The value of a <code>QName</code> contains a <strong>Namespace
40 * URI</strong>, <strong>local part</strong> and
41 * <strong>prefix</strong>.</p>
43 * <p>The prefix is included in <code>QName</code> to retain lexical
44 * information <strong><em>when present</em></strong> in an {@link
45 * javax.xml.transform.Source XML input source}. The prefix is
46 * <strong><em>NOT</em></strong> used in {@link #equals(Object)
47 * QName.equals(Object)} or to compute the {@link #hashCode()
48 * QName.hashCode()}. Equality and the hash code are defined using
49 * <strong><em>only</em></strong> the Namespace URI and local part.</p>
51 * <p>If not specified, the Namespace URI is set to {@link
52 * javax.xml.XMLConstants#NULL_NS_URI XMLConstants.NULL_NS_URI}.
53 * If not specified, the prefix is set to {@link
54 * javax.xml.XMLConstants#DEFAULT_NS_PREFIX
55 * XMLConstants.DEFAULT_NS_PREFIX}.</p>
57 * <p><code>QName</code> is immutable.</p>
59 * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a>
60 * @version $Revision: 754581 $, $Date: 2009-03-14 18:32:39 -0700 (Sat, 14 Mar 2009) $
61 * @see <a href="http://www.w3.org/TR/xmlschema-2/#QName">XML Schema Part2: Datatypes specification</a>
62 * @see <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces in XML</a>
63 * @see <a href="http://www.w3.org/XML/xml-names-19990114-errata">Namespaces in XML Errata</a>
67 public class QName implements Serializable {
70 * <p>Stream Unique Identifier.</p>
72 * <p>To enable the compatibility <code>serialVersionUID</code>
73 * set the System Property
74 * <code>org.apache.xml.namespace.QName.useCompatibleSerialVersionUID</code>
75 * to a value of "1.0".</p>
77 private static final long serialVersionUID;
80 * <p>The original default Stream Unique Identifier.</p>
82 private static final long defaultSerialVersionUID = -9120448754896609940L;
85 * <p>The compatibility Stream Unique Identifier that was introduced
86 * with Java 5 SE SDK.</p>
88 private static final long compatabilitySerialVersionUID = 4418622981026545151L;
91 String compatPropValue = null;
93 compatPropValue = (String)AccessController.doPrivileged(
94 new PrivilegedAction() {
96 return System.getProperty("org.apache.xml.namespace.QName.useCompatibleSerialVersionUID");
100 catch (Exception e) {}
101 // If 1.0 use compatibility serialVersionUID
102 serialVersionUID = !"1.0".equals(compatPropValue) ? defaultSerialVersionUID : compatabilitySerialVersionUID;
106 * <p>Namespace URI of this <code>QName</code>.</p>
108 private final String namespaceURI;
111 * <p>local part of this <code>QName</code>.</p>
113 private final String localPart;
116 * <p>prefix of this <code>QName</code>.</p>
118 private String prefix;
121 * <p><code>String</code> representation of this <code>QName</code>.</p>
123 private transient String qNameAsString;
126 * <p><code>QName</code> constructor specifying the Namespace URI
127 * and local part.</p>
129 * <p>If the Namespace URI is <code>null</code>, it is set to
130 * {@link javax.xml.XMLConstants#NULL_NS_URI
131 * XMLConstants.NULL_NS_URI}. This value represents no
132 * explicitly defined Namespace as defined by the <a
133 * href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces
134 * in XML</a> specification. This action preserves compatible
135 * behavior with QName 1.0. Explicitly providing the {@link
136 * javax.xml.XMLConstants#NULL_NS_URI
137 * XMLConstants.NULL_NS_URI} value is the preferred coding
140 * <p>If the local part is <code>null</code> an
141 * <code>IllegalArgumentException</code> is thrown.
142 * A local part of "" is allowed to preserve
143 * compatible behavior with QName 1.0. </p>
145 * <p>When using this constructor, the prefix is set to {@link
146 * javax.xml.XMLConstants#DEFAULT_NS_PREFIX
147 * XMLConstants.DEFAULT_NS_PREFIX}.</p>
149 * <p>The Namespace URI is not validated as a
150 * <a href="http://www.ietf.org/rfc/rfc2396.txt">URI reference</a>.
151 * The local part is not validated as a
152 * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a>
153 * as specified in <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces
156 * @param namespaceURI Namespace URI of the <code>QName</code>
157 * @param localPart local part of the <code>QName</code>
159 * @see #QName(String namespaceURI, String localPart, String
160 * prefix) QName(String namespaceURI, String localPart, String
163 public QName(final String namespaceURI, final String localPart) {
164 this(namespaceURI, localPart, XMLConstants.DEFAULT_NS_PREFIX);
168 * <p><code>QName</code> constructor specifying the Namespace URI,
169 * local part and prefix.</p>
171 * <p>If the Namespace URI is <code>null</code>, it is set to
172 * {@link javax.xml.XMLConstants#NULL_NS_URI
173 * XMLConstants.NULL_NS_URI}. This value represents no
174 * explicitly defined Namespace as defined by the <a
175 * href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces
176 * in XML</a> specification. This action preserves compatible
177 * behavior with QName 1.0. Explicitly providing the {@link
178 * javax.xml.XMLConstants#NULL_NS_URI
179 * XMLConstants.NULL_NS_URI} value is the preferred coding
182 * <p>If the local part is <code>null</code> an
183 * <code>IllegalArgumentException</code> is thrown.
184 * A local part of "" is allowed to preserve
185 * compatible behavior with QName 1.0. </p>
187 * <p>If the prefix is <code>null</code>, an
188 * <code>IllegalArgumentException</code> is thrown. Use {@link
189 * javax.xml.XMLConstants#DEFAULT_NS_PREFIX
190 * XMLConstants.DEFAULT_NS_PREFIX} to explicitly indicate that no
191 * prefix is present or the prefix is not relevant.</p>
193 * <p>The Namespace URI is not validated as a
194 * <a href="http://www.ietf.org/rfc/rfc2396.txt">URI reference</a>.
195 * The local part and prefix are not validated as a
196 * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a>
197 * as specified in <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces
200 * @param namespaceURI Namespace URI of the <code>QName</code>
201 * @param localPart local part of the <code>QName</code>
202 * @param prefix prefix of the <code>QName</code>
204 public QName(String namespaceURI, String localPart, String prefix) {
206 // map null Namespace URI to default to preserve compatibility with QName 1.0
207 if (namespaceURI == null) {
208 this.namespaceURI = XMLConstants.NULL_NS_URI;
210 this.namespaceURI = namespaceURI;
213 // local part is required. "" is allowed to preserve compatibility with QName 1.0
214 if (localPart == null) {
215 throw new IllegalArgumentException("local part cannot be \"null\" when creating a QName");
217 this.localPart = localPart;
219 // prefix is required
220 if (prefix == null) {
221 throw new IllegalArgumentException("prefix cannot be \"null\" when creating a QName");
223 this.prefix = prefix;
227 * <p><code>QName</code> constructor specifying the local part.</p>
229 * <p>If the local part is <code>null</code> an
230 * <code>IllegalArgumentException</code> is thrown.
231 * A local part of "" is allowed to preserve
232 * compatible behavior with QName 1.0. </p>
234 * <p>When using this constructor, the Namespace URI is set to
235 * {@link javax.xml.XMLConstants#NULL_NS_URI
236 * XMLConstants.NULL_NS_URI} and the prefix is set to {@link
237 * javax.xml.XMLConstants#DEFAULT_NS_PREFIX
238 * XMLConstants.DEFAULT_NS_PREFIX}.</p>
240 * <p><em>In an XML context, all Element and Attribute names exist
241 * in the context of a Namespace. Making this explicit during the
242 * construction of a <code>QName</code> helps prevent hard to
243 * diagnosis XML validity errors. The constructors {@link
244 * #QName(String namespaceURI, String localPart) QName(String
245 * namespaceURI, String localPart)} and
246 * {@link #QName(String namespaceURI, String localPart, String prefix)}
247 * are preferred.</em></p>
249 * <p>The local part is not validated as a
250 * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a>
251 * as specified in <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces
254 * @param localPart local part of the <code>QName</code>
255 * @see #QName(String namespaceURI, String localPart) QName(String
256 * namespaceURI, String localPart)
257 * @see #QName(String namespaceURI, String localPart, String
258 * prefix) QName(String namespaceURI, String localPart, String
261 public QName(String localPart) {
263 XMLConstants.NULL_NS_URI,
265 XMLConstants.DEFAULT_NS_PREFIX);
269 * <p>Get the Namespace URI of this <code>QName</code>.</p>
271 * @return Namespace URI of this <code>QName</code>
273 public String getNamespaceURI() {
278 * <p>Get the local part of this <code>QName</code>.</p>
280 * @return local part of this <code>QName</code>
282 public String getLocalPart() {
287 * <p>Get the prefix of this <code>QName</code>.</p>
289 * <p>The prefix assigned to a <code>QName</code> might
290 * <strong><em>NOT</em></strong> be valid in a different
291 * context. For example, a <code>QName</code> may be assigned a
292 * prefix in the context of parsing a document but that prefix may
293 * be invalid in the context of a different document.</p>
295 * @return prefix of this <code>QName</code>
297 public String getPrefix() {
302 * <p>Test this <code>QName</code> for equality with another
303 * <code>Object</code>.</p>
305 * <p>If the <code>Object</code> to be tested is not a
306 * <code>QName</code> or is <code>null</code>, then this method
307 * returns <code>false</code>.</p>
309 * <p>Two <code>QName</code>s are considered equal if and only if
310 * both the Namespace URI and local part are equal. This method
311 * uses <code>String.equals()</code> to check equality of the
312 * Namespace URI and local part. The prefix is
313 * <strong><em>NOT</em></strong> used to determine equality.</p>
315 * <p>This method satisfies the general contract of {@link
316 * java.lang.Object#equals(Object) Object.equals(Object)}</p>
318 * @param objectToTest the <code>Object</code> to test for
319 * equality with this <code>QName</code>
320 * @return <code>true</code> if the given <code>Object</code> is
321 * equal to this <code>QName</code> else <code>false</code>
323 public final boolean equals(Object objectToTest) {
324 // Is this the same object?
325 if (objectToTest == this) {
329 if (objectToTest instanceof QName) {
330 QName qName = (QName) objectToTest;
331 return localPart.equals(qName.localPart) && namespaceURI.equals(qName.namespaceURI);
337 * <p>Generate the hash code for this <code>QName</code>.</p>
339 * <p>The hash code is calculated using both the Namespace URI and
340 * the local part of the <code>QName</code>. The prefix is
341 * <strong><em>NOT</em></strong> used to calculate the hash
344 * <p>This method satisfies the general contract of {@link
345 * java.lang.Object#hashCode() Object.hashCode()}.</p>
347 * @return hash code for this <code>QName</code> <code>Object</code>
349 public final int hashCode() {
350 return namespaceURI.hashCode() ^ localPart.hashCode();
354 * <p><code>String</code> representation of this
355 * <code>QName</code>.</p>
357 * <p>The commonly accepted way of representing a <code>QName</code>
358 * as a <code>String</code> was <a href="http://jclark.com/xml/xmlns.htm">defined</a>
359 * by James Clark. Although this is not a <em>standard</em>
360 * specification, it is in common use, e.g. {@link javax.xml.transform.Transformer#setParameter(String name, Object value)}.
361 * This implementation represents a <code>QName</code> as:
362 * "{" + Namespace URI + "}" + local part. If the Namespace URI
363 * <code>.equals(XMLConstants.NULL_NS_URI)</code>, only the
364 * local part is returned. An appropriate use of this method is
365 * for debugging or logging for human consumption.</p>
367 * <p>Note the prefix value is <strong><em>NOT</em></strong>
368 * returned as part of the <code>String</code> representation.</p>
370 * <p>This method satisfies the general contract of {@link
371 * java.lang.Object#toString() Object.toString()}.</p>
373 * @return <code>String</code> representation of this <code>QName</code>
375 public String toString() {
376 String _qNameAsString = qNameAsString;
377 if (_qNameAsString == null) {
378 final int nsLength = namespaceURI.length();
380 _qNameAsString = localPart;
383 StringBuilder buffer = new StringBuilder(nsLength + localPart.length() + 2);
385 buffer.append(namespaceURI);
387 buffer.append(localPart);
388 _qNameAsString = buffer.toString();
390 qNameAsString = _qNameAsString;
392 return _qNameAsString;
396 * <p><code>QName</code> derived from parsing the formatted
397 * <code>String</code>.</p>
399 * <p>If the <code>String</code> is <code>null</code> or does not conform to
400 * {@link #toString() QName.toString()} formatting, an
401 * <code>IllegalArgumentException</code> is thrown.</p>
403 * <p><em>The <code>String</code> <strong>MUST</strong> be in the
404 * form returned by {@link #toString() QName.toString()}.</em></p>
406 * <p>The commonly accepted way of representing a <code>QName</code>
407 * as a <code>String</code> was <a href="http://jclark.com/xml/xmlns.htm">defined</a>
408 * by James Clark. Although this is not a <em>standard</em>
409 * specification, it is in common use, e.g. {@link javax.xml.transform.Transformer#setParameter(String name, Object value)}.
410 * This implementation parses a <code>String</code> formatted
411 * as: "{" + Namespace URI + "}" + local part. If the Namespace
412 * URI <code>.equals(XMLConstants.NULL_NS_URI)</code>, only the
413 * local part should be provided.</p>
415 * <p>The prefix value <strong><em>CANNOT</em></strong> be
416 * represented in the <code>String</code> and will be set to
417 * {@link javax.xml.XMLConstants#DEFAULT_NS_PREFIX
418 * XMLConstants.DEFAULT_NS_PREFIX}.</p>
420 * <p>This method does not do full validation of the resulting
421 * <code>QName</code>.
422 * <p>The Namespace URI is not validated as a
423 * <a href="http://www.ietf.org/rfc/rfc2396.txt">URI reference</a>.
424 * The local part is not validated as a
425 * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a>
427 * <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces in XML</a>.</p>
429 * @param qNameAsString <code>String</code> representation
430 * of the <code>QName</code>
431 * @return <code>QName</code> corresponding to the given <code>String</code>
432 * @see #toString() QName.toString()
434 public static QName valueOf(String qNameAsString) {
437 if (qNameAsString == null) {
438 throw new IllegalArgumentException("cannot create QName from \"null\" or \"\" String");
441 // "" local part is valid to preserve compatible behavior with QName 1.0
442 if (qNameAsString.length() == 0) {
444 XMLConstants.NULL_NS_URI,
446 XMLConstants.DEFAULT_NS_PREFIX);
450 if (qNameAsString.charAt(0) != '{') {
452 XMLConstants.NULL_NS_URI,
454 XMLConstants.DEFAULT_NS_PREFIX);
457 // Namespace URI improperly specified?
458 if (qNameAsString.startsWith("{" + XMLConstants.NULL_NS_URI + "}")) {
459 throw new IllegalArgumentException(
460 "Namespace URI .equals(XMLConstants.NULL_NS_URI), "
461 + ".equals(\"" + XMLConstants.NULL_NS_URI + "\"), "
462 + "only the local part, "
463 + "\"" + qNameAsString.substring(2 + XMLConstants.NULL_NS_URI.length()) + "\", "
464 + "should be provided.");
467 // Namespace URI and local part specified
468 int endOfNamespaceURI = qNameAsString.indexOf('}');
469 if (endOfNamespaceURI == -1) {
470 throw new IllegalArgumentException(
471 "cannot create QName from \""
473 + "\", missing closing \"}\"");
476 qNameAsString.substring(1, endOfNamespaceURI),
477 qNameAsString.substring(endOfNamespaceURI + 1),
478 XMLConstants.DEFAULT_NS_PREFIX);
482 * For old versions of QName which didn't have a prefix field,
483 * <code>ObjectInputStream.defaultReadObject()</code> will initialize
484 * the prefix to <code>null</code> instead of the empty string. This
485 * method fixes up the prefix field if it didn't exist in the serialized
488 private void readObject(ObjectInputStream in)
489 throws IOException, ClassNotFoundException {
490 in.defaultReadObject();
491 if (prefix == null) {
492 prefix = XMLConstants.DEFAULT_NS_PREFIX;