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