1 /*
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
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17 
18 // $Id: QName.java 754581 2009-03-15 01:32:39Z mrglavas $
19 
20 package javax.xml.namespace;
21 
22 import java.io.IOException;
23 import java.io.ObjectInputStream;
24 import java.io.Serializable;
25 import javax.xml.XMLConstants;
26 
27 /**
28  * <p><code>QName</code> represents a <strong>qualified name</strong>
29  * as defined in the XML specifications: <a
30  * href="http://www.w3.org/TR/xmlschema-2/#QName">XML Schema Part2:
31  * Datatypes specification</a>, <a
32  * href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces
33  * in XML</a>, <a
34  * href="http://www.w3.org/XML/xml-names-19990114-errata">Namespaces
35  * in XML Errata</a>.</p>
36  *
37  * <p>The value of a <code>QName</code> contains a <strong>Namespace
38  * URI</strong>, <strong>local part</strong> and
39  * <strong>prefix</strong>.</p>
40  *
41  * <p>The prefix is included in <code>QName</code> to retain lexical
42  * information <strong><em>when present</em></strong> in an {@link
43  * javax.xml.transform.Source XML input source}. The prefix is
44  * <strong><em>NOT</em></strong> used in {@link #equals(Object)
45  * QName.equals(Object)} or to compute the {@link #hashCode()
46  * QName.hashCode()}.  Equality and the hash code are defined using
47  * <strong><em>only</em></strong> the Namespace URI and local part.</p>
48  *
49  * <p>If not specified, the Namespace URI is set to {@link
50  * javax.xml.XMLConstants#NULL_NS_URI XMLConstants.NULL_NS_URI}.
51  * If not specified, the prefix is set to {@link
52  * javax.xml.XMLConstants#DEFAULT_NS_PREFIX
53  * XMLConstants.DEFAULT_NS_PREFIX}.</p>
54  *
55  * <p><code>QName</code> is immutable.</p>
56  *
57  * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a>
58  * @version $Revision: 754581 $, $Date: 2009-03-14 18:32:39 -0700 (Sat, 14 Mar 2009) $
59  * @see <a href="http://www.w3.org/TR/xmlschema-2/#QName">XML Schema Part2: Datatypes specification</a>
60  * @see <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces in XML</a>
61  * @see <a href="http://www.w3.org/XML/xml-names-19990114-errata">Namespaces in XML Errata</a>
62  * @since 1.5
63  */
64 
65 public class QName implements Serializable {
66 
67     /**
68      * <p>Stream Unique Identifier.</p>
69      *
70      * <p>To enable the compatibility <code>serialVersionUID</code>
71      * set the System Property
72      * <code>org.apache.xml.namespace.QName.useCompatibleSerialVersionUID</code>
73      * to a value of "1.0".</p>
74      */
75     private static final long serialVersionUID;
76 
77     /**
78      * <p>The original default Stream Unique Identifier.</p>
79      */
80     private static final long defaultSerialVersionUID = -9120448754896609940L;
81 
82     /**
83      * <p>The compatibility Stream Unique Identifier that was introduced
84      * with Java 5 SE SDK.</p>
85      */
86     private static final long compatibilitySerialVersionUID = 4418622981026545151L;
87 
88     static {
89         String compatPropValue = System.getProperty("org.apache.xml.namespace.QName.useCompatibleSerialVersionUID");
90         // If 1.0 use compatibility serialVersionUID
91         serialVersionUID = !"1.0".equals(compatPropValue) ? defaultSerialVersionUID : compatibilitySerialVersionUID;
92     }
93 
94     /**
95      * <p>Namespace URI of this <code>QName</code>.</p>
96      */
97     private final String namespaceURI;
98 
99     /**
100      * <p>local part of this <code>QName</code>.</p>
101      */
102     private final String localPart;
103 
104     /**
105      * <p>prefix of this <code>QName</code>.</p>
106      */
107     private String prefix;
108 
109     /**
110      * <p><code>String</code> representation of this <code>QName</code>.</p>
111      */
112     private transient String qNameAsString;
113 
114     /**
115      * <p><code>QName</code> constructor specifying the Namespace URI
116      * and local part.</p>
117      *
118      * <p>If the Namespace URI is <code>null</code>, it is set to
119      * {@link javax.xml.XMLConstants#NULL_NS_URI
120      * XMLConstants.NULL_NS_URI}.  This value represents no
121      * explicitly defined Namespace as defined by the <a
122      * href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces
123      * in XML</a> specification.  This action preserves compatible
124      * behavior with QName 1.0.  Explicitly providing the {@link
125      * javax.xml.XMLConstants#NULL_NS_URI
126      * XMLConstants.NULL_NS_URI} value is the preferred coding
127      * style.</p>
128      *
129      * <p>If the local part is <code>null</code> an
130      * <code>IllegalArgumentException</code> is thrown.
131      * A local part of "" is allowed to preserve
132      * compatible behavior with QName 1.0. </p>
133      *
134      * <p>When using this constructor, the prefix is set to {@link
135      * javax.xml.XMLConstants#DEFAULT_NS_PREFIX
136      * XMLConstants.DEFAULT_NS_PREFIX}.</p>
137      *
138      * <p>The Namespace URI is not validated as a
139      * <a href="http://www.ietf.org/rfc/rfc2396.txt">URI reference</a>.
140      * The local part is not validated as a
141      * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a>
142      * as specified in <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces
143      * in XML</a>.</p>
144      *
145      * @param namespaceURI Namespace URI of the <code>QName</code>
146      * @param localPart    local part of the <code>QName</code>
147      *
148      * @see #QName(String namespaceURI, String localPart, String
149      * prefix) QName(String namespaceURI, String localPart, String
150      * prefix)
151      */
QName(final String namespaceURI, final String localPart)152     public QName(final String namespaceURI, final String localPart) {
153         this(namespaceURI, localPart, XMLConstants.DEFAULT_NS_PREFIX);
154     }
155 
156     /**
157      * <p><code>QName</code> constructor specifying the Namespace URI,
158      * local part and prefix.</p>
159      *
160      * <p>If the Namespace URI is <code>null</code>, it is set to
161      * {@link javax.xml.XMLConstants#NULL_NS_URI
162      * XMLConstants.NULL_NS_URI}.  This value represents no
163      * explicitly defined Namespace as defined by the <a
164      * href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces
165      * in XML</a> specification.  This action preserves compatible
166      * behavior with QName 1.0.  Explicitly providing the {@link
167      * javax.xml.XMLConstants#NULL_NS_URI
168      * XMLConstants.NULL_NS_URI} value is the preferred coding
169      * style.</p>
170      *
171      * <p>If the local part is <code>null</code> an
172      * <code>IllegalArgumentException</code> is thrown.
173      * A local part of "" is allowed to preserve
174      * compatible behavior with QName 1.0. </p>
175      *
176      * <p>If the prefix is <code>null</code>, an
177      * <code>IllegalArgumentException</code> is thrown.  Use {@link
178      * javax.xml.XMLConstants#DEFAULT_NS_PREFIX
179      * XMLConstants.DEFAULT_NS_PREFIX} to explicitly indicate that no
180      * prefix is present or the prefix is not relevant.</p>
181      *
182      * <p>The Namespace URI is not validated as a
183      * <a href="http://www.ietf.org/rfc/rfc2396.txt">URI reference</a>.
184      * The local part and prefix are not validated as a
185      * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a>
186      * as specified in <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces
187      * in XML</a>.</p>
188      *
189      * @param namespaceURI Namespace URI of the <code>QName</code>
190      * @param localPart    local part of the <code>QName</code>
191      * @param prefix       prefix of the <code>QName</code>
192      */
QName(String namespaceURI, String localPart, String prefix)193     public QName(String namespaceURI, String localPart, String prefix) {
194 
195         // map null Namespace URI to default to preserve compatibility with QName 1.0
196         if (namespaceURI == null) {
197             this.namespaceURI = XMLConstants.NULL_NS_URI;
198         } else {
199             this.namespaceURI = namespaceURI;
200         }
201 
202         // local part is required.  "" is allowed to preserve compatibility with QName 1.0
203         if (localPart == null) {
204             throw new IllegalArgumentException("local part cannot be \"null\" when creating a QName");
205         }
206         this.localPart = localPart;
207 
208         // prefix is required
209         if (prefix == null) {
210             throw new IllegalArgumentException("prefix cannot be \"null\" when creating a QName");
211         }
212         this.prefix = prefix;
213     }
214 
215     /**
216      * <p><code>QName</code> constructor specifying the local part.</p>
217      *
218      * <p>If the local part is <code>null</code> an
219      * <code>IllegalArgumentException</code> is thrown.
220      * A local part of "" is allowed to preserve
221      * compatible behavior with QName 1.0. </p>
222      *
223      * <p>When using this constructor, the Namespace URI is set to
224      * {@link javax.xml.XMLConstants#NULL_NS_URI
225      * XMLConstants.NULL_NS_URI} and the prefix is set to {@link
226      * javax.xml.XMLConstants#DEFAULT_NS_PREFIX
227      * XMLConstants.DEFAULT_NS_PREFIX}.</p>
228      *
229      * <p><em>In an XML context, all Element and Attribute names exist
230      * in the context of a Namespace.  Making this explicit during the
231      * construction of a <code>QName</code> helps prevent hard to
232      * diagnosis XML validity errors.  The constructors {@link
233      * #QName(String namespaceURI, String localPart) QName(String
234      * namespaceURI, String localPart)} and
235      * {@link #QName(String namespaceURI, String localPart, String prefix)}
236      * are preferred.</em></p>
237      *
238      * <p>The local part is not validated as a
239      * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a>
240      * as specified in <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces
241      * in XML</a>.</p>
242      *
243      * @param localPart local part of the <code>QName</code>
244      * @see #QName(String namespaceURI, String localPart) QName(String
245      * namespaceURI, String localPart)
246      * @see #QName(String namespaceURI, String localPart, String
247      * prefix) QName(String namespaceURI, String localPart, String
248      * prefix)
249      */
QName(String localPart)250     public QName(String localPart) {
251         this(
252             XMLConstants.NULL_NS_URI,
253             localPart,
254             XMLConstants.DEFAULT_NS_PREFIX);
255     }
256 
257     /**
258      * <p>Get the Namespace URI of this <code>QName</code>.</p>
259      *
260      * @return Namespace URI of this <code>QName</code>
261      */
getNamespaceURI()262     public String getNamespaceURI() {
263         return namespaceURI;
264     }
265 
266     /**
267      * <p>Get the local part of this <code>QName</code>.</p>
268      *
269      *  @return local part of this <code>QName</code>
270      */
getLocalPart()271     public String getLocalPart() {
272         return localPart;
273     }
274 
275     /**
276      * <p>Get the prefix of this <code>QName</code>.</p>
277      *
278      * <p>The prefix assigned to a <code>QName</code> might
279      * <strong><em>NOT</em></strong> be valid in a different
280      * context. For example, a <code>QName</code> may be assigned a
281      * prefix in the context of parsing a document but that prefix may
282      * be invalid in the context of a different document.</p>
283      *
284      *  @return prefix of this <code>QName</code>
285      */
getPrefix()286     public String getPrefix() {
287         return prefix;
288     }
289 
290     /**
291      * <p>Test this <code>QName</code> for equality with another
292      * <code>Object</code>.</p>
293      *
294      * <p>If the <code>Object</code> to be tested is not a
295      * <code>QName</code> or is <code>null</code>, then this method
296      * returns <code>false</code>.</p>
297      *
298      * <p>Two <code>QName</code>s are considered equal if and only if
299      * both the Namespace URI and local part are equal. This method
300      * uses <code>String.equals()</code> to check equality of the
301      * Namespace URI and local part. The prefix is
302      * <strong><em>NOT</em></strong> used to determine equality.</p>
303      *
304      * <p>This method satisfies the general contract of {@link
305      * java.lang.Object#equals(Object) Object.equals(Object)}</p>
306      *
307      * @param objectToTest the <code>Object</code> to test for
308      * equality with this <code>QName</code>
309      * @return <code>true</code> if the given <code>Object</code> is
310      * equal to this <code>QName</code> else <code>false</code>
311      */
equals(Object objectToTest)312     public final boolean equals(Object objectToTest) {
313         // Is this the same object?
314         if (objectToTest == this) {
315             return true;
316         }
317         // Is this a QName?
318         if (objectToTest instanceof QName) {
319             QName qName = (QName) objectToTest;
320             return localPart.equals(qName.localPart) && namespaceURI.equals(qName.namespaceURI);
321         }
322         return false;
323     }
324 
325     /**
326      * <p>Generate the hash code for this <code>QName</code>.</p>
327      *
328      * <p>The hash code is calculated using both the Namespace URI and
329      * the local part of the <code>QName</code>.  The prefix is
330      * <strong><em>NOT</em></strong> used to calculate the hash
331      * code.</p>
332      *
333      * <p>This method satisfies the general contract of {@link
334      * java.lang.Object#hashCode() Object.hashCode()}.</p>
335      *
336      * @return hash code for this <code>QName</code> <code>Object</code>
337      */
hashCode()338     public final int hashCode() {
339         return namespaceURI.hashCode() ^ localPart.hashCode();
340     }
341 
342     /**
343      * <p><code>String</code> representation of this
344      * <code>QName</code>.</p>
345      *
346      * <p>The commonly accepted way of representing a <code>QName</code>
347      * as a <code>String</code> was <a href="http://jclark.com/xml/xmlns.htm">defined</a>
348      * by James Clark.  Although this is not a <em>standard</em>
349      * specification, it is in common use,  e.g. {@link javax.xml.transform.Transformer#setParameter(String name, Object value)}.
350      * This implementation represents a <code>QName</code> as:
351      * "{" + Namespace URI + "}" + local part.  If the Namespace URI
352      * <code>.equals(XMLConstants.NULL_NS_URI)</code>, only the
353      * local part is returned.  An appropriate use of this method is
354      * for debugging or logging for human consumption.</p>
355      *
356      * <p>Note the prefix value is <strong><em>NOT</em></strong>
357      * returned as part of the <code>String</code> representation.</p>
358      *
359      * <p>This method satisfies the general contract of {@link
360      * java.lang.Object#toString() Object.toString()}.</p>
361      *
362      * @return <code>String</code> representation of this <code>QName</code>
363      */
toString()364     public String toString() {
365         String _qNameAsString = qNameAsString;
366         if (_qNameAsString == null) {
367             final int nsLength = namespaceURI.length();
368             if (nsLength == 0) {
369                 _qNameAsString = localPart;
370             }
371             else {
372                 StringBuilder buffer = new StringBuilder(nsLength + localPart.length() + 2);
373                 buffer.append('{');
374                 buffer.append(namespaceURI);
375                 buffer.append('}');
376                 buffer.append(localPart);
377                 _qNameAsString = buffer.toString();
378             }
379             qNameAsString = _qNameAsString;
380         }
381         return _qNameAsString;
382     }
383 
384     /**
385      * <p><code>QName</code> derived from parsing the formatted
386      * <code>String</code>.</p>
387      *
388      * <p>If the <code>String</code> is <code>null</code> or does not conform to
389      * {@link #toString() QName.toString()} formatting, an
390      * <code>IllegalArgumentException</code> is thrown.</p>
391      *
392      * <p><em>The <code>String</code> <strong>MUST</strong> be in the
393      * form returned by {@link #toString() QName.toString()}.</em></p>
394      *
395      * <p>The commonly accepted way of representing a <code>QName</code>
396      * as a <code>String</code> was <a href="http://jclark.com/xml/xmlns.htm">defined</a>
397      * by James Clark.  Although this is not a <em>standard</em>
398      * specification, it is in common use,  e.g. {@link javax.xml.transform.Transformer#setParameter(String name, Object value)}.
399      * This implementation parses a <code>String</code> formatted
400      * as: "{" + Namespace URI + "}" + local part.  If the Namespace
401      * URI <code>.equals(XMLConstants.NULL_NS_URI)</code>, only the
402      * local part should be provided.</p>
403      *
404      * <p>The prefix value <strong><em>CANNOT</em></strong> be
405      * represented in the <code>String</code> and will be set to
406      * {@link javax.xml.XMLConstants#DEFAULT_NS_PREFIX
407      * XMLConstants.DEFAULT_NS_PREFIX}.</p>
408      *
409      * <p>This method does not do full validation of the resulting
410      * <code>QName</code>.
411      * <p>The Namespace URI is not validated as a
412      * <a href="http://www.ietf.org/rfc/rfc2396.txt">URI reference</a>.
413      * The local part is not validated as a
414      * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a>
415      * as specified in
416      * <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces in XML</a>.</p>
417      *
418      * @param qNameAsString <code>String</code> representation
419      * of the <code>QName</code>
420      * @return <code>QName</code> corresponding to the given <code>String</code>
421      * @see #toString() QName.toString()
422      */
valueOf(String qNameAsString)423     public static QName valueOf(String qNameAsString) {
424 
425         // null is not valid
426         if (qNameAsString == null) {
427             throw new IllegalArgumentException("cannot create QName from \"null\" or \"\" String");
428         }
429 
430         // "" local part is valid to preserve compatible behavior with QName 1.0
431         if (qNameAsString.length() == 0) {
432             return new QName(
433                 XMLConstants.NULL_NS_URI,
434                 qNameAsString,
435                 XMLConstants.DEFAULT_NS_PREFIX);
436         }
437 
438         // local part only?
439         if (qNameAsString.charAt(0) != '{') {
440             return new QName(
441                 XMLConstants.NULL_NS_URI,
442                 qNameAsString,
443                 XMLConstants.DEFAULT_NS_PREFIX);
444         }
445 
446         // Namespace URI improperly specified?
447         if (qNameAsString.startsWith("{" + XMLConstants.NULL_NS_URI + "}")) {
448             throw new IllegalArgumentException(
449                 "Namespace URI .equals(XMLConstants.NULL_NS_URI), "
450                 + ".equals(\"" + XMLConstants.NULL_NS_URI + "\"), "
451                 + "only the local part, "
452                 + "\"" + qNameAsString.substring(2 + XMLConstants.NULL_NS_URI.length()) + "\", "
453                 + "should be provided.");
454         }
455 
456         // Namespace URI and local part specified
457         int endOfNamespaceURI = qNameAsString.indexOf('}');
458         if (endOfNamespaceURI == -1) {
459             throw new IllegalArgumentException(
460                 "cannot create QName from \""
461                     + qNameAsString
462                     + "\", missing closing \"}\"");
463         }
464         return new QName(
465             qNameAsString.substring(1, endOfNamespaceURI),
466             qNameAsString.substring(endOfNamespaceURI + 1),
467             XMLConstants.DEFAULT_NS_PREFIX);
468     }
469 
470     /*
471      * For old versions of QName which didn't have a prefix field,
472      * <code>ObjectInputStream.defaultReadObject()</code> will initialize
473      * the prefix to <code>null</code> instead of the empty string. This
474      * method fixes up the prefix field if it didn't exist in the serialized
475      * object.
476      */
readObject(ObjectInputStream in)477     private void readObject(ObjectInputStream in)
478         throws IOException, ClassNotFoundException {
479         in.defaultReadObject();
480         if (prefix == null) {
481             prefix = XMLConstants.DEFAULT_NS_PREFIX;
482         }
483     }
484 }
485