1 /* 2 * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.xml.namespace; 27 28 import java.io.Serializable; 29 import java.security.AccessController; 30 import java.security.PrivilegedAction; 31 32 import javax.xml.XMLConstants; 33 34 /** 35 * <p><code>QName</code> represents a <strong>qualified name</strong> 36 * as defined in the XML specifications: <a 37 * href="http://www.w3.org/TR/xmlschema-2/#QName">XML Schema Part2: 38 * Datatypes specification</a>, <a 39 * href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces 40 * in XML</a>, <a 41 * href="http://www.w3.org/XML/xml-names-19990114-errata">Namespaces 42 * in XML Errata</a>.</p> 43 * 44 * <p>The value of a <code>QName</code> contains a <strong>Namespace 45 * URI</strong>, <strong>local part</strong> and 46 * <strong>prefix</strong>.</p> 47 * 48 * <p>The prefix is included in <code>QName</code> to retain lexical 49 * information <strong><em>when present</em></strong> in an {@link 50 * javax.xml.transform.Source XML input source}. The prefix is 51 * <strong><em>NOT</em></strong> used in {@link #equals(Object) 52 * QName.equals(Object)} or to compute the {@link #hashCode() 53 * QName.hashCode()}. Equality and the hash code are defined using 54 * <strong><em>only</em></strong> the Namespace URI and local part.</p> 55 * 56 * <p>If not specified, the Namespace URI is set to {@link 57 * javax.xml.XMLConstants#NULL_NS_URI XMLConstants.NULL_NS_URI}. 58 * If not specified, the prefix is set to {@link 59 * javax.xml.XMLConstants#DEFAULT_NS_PREFIX 60 * XMLConstants.DEFAULT_NS_PREFIX}.</p> 61 * 62 * <p><code>QName</code> is immutable.</p> 63 * 64 * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a> 65 * @version $Revision: 1.8 $, $Date: 2010/03/18 03:06:17 $ 66 * @see <a href="http://www.w3.org/TR/xmlschema-2/#QName"> 67 * XML Schema Part2: Datatypes specification</a> 68 * @see <a href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames"> 69 * Namespaces in XML</a> 70 * @see <a href="http://www.w3.org/XML/xml-names-19990114-errata"> 71 * Namespaces in XML Errata</a> 72 * @since 1.5 73 */ 74 75 public class QName implements Serializable { 76 77 /** 78 * <p>Stream Unique Identifier.</p> 79 * 80 * <p>Due to a historical defect, QName was released with multiple 81 * serialVersionUID values even though its serialization was the 82 * same.</p> 83 * 84 * <p>To workaround this issue, serialVersionUID is set with either 85 * a default value or a compatibility value. To use the 86 * compatiblity value, set the system property:</p> 87 * 88 * <code>com.sun.xml.namespace.QName.useCompatibleSerialVersionUID=1.0</code> 89 * 90 * <p>This workaround was inspired by classes in the javax.management 91 * package, e.g. ObjectName, etc. 92 * See CR6267224 for original defect report.</p> 93 */ 94 private static final long serialVersionUID; 95 /** 96 * <p>Default <code>serialVersionUID</code> value.</p> 97 */ 98 private static final long defaultSerialVersionUID = -9120448754896609940L; 99 /** 100 * <p>Compatibility <code>serialVersionUID</code> value.</p> 101 */ 102 private static final long compatibleSerialVersionUID = 4418622981026545151L; 103 /** 104 * <p>Flag to use default or campatible serialVersionUID.</p> 105 */ 106 private static boolean useDefaultSerialVersionUID = true; 107 static { 108 try { 109 // use a privileged block as reading a system property 110 String valueUseCompatibleSerialVersionUID = (String) AccessController.doPrivileged( 111 new PrivilegedAction() { 112 public Object run() { 113 return System.getProperty("com.sun.xml.namespace.QName.useCompatibleSerialVersionUID"); 114 } 115 } 116 ); 117 useDefaultSerialVersionUID = (valueUseCompatibleSerialVersionUID != null && valueUseCompatibleSerialVersionUID.equals("1.0")) ? false : true; 118 } catch (Exception exception) { 119 // use default if any Exceptions 120 useDefaultSerialVersionUID = true; 121 } 122 123 // set serialVersionUID to desired value 124 if (useDefaultSerialVersionUID) { 125 serialVersionUID = defaultSerialVersionUID; 126 } else { 127 serialVersionUID = compatibleSerialVersionUID; 128 } 129 } 130 131 /** 132 * <p>Namespace URI of this <code>QName</code>.</p> 133 */ 134 private final String namespaceURI; 135 136 /** 137 * <p>local part of this <code>QName</code>.</p> 138 */ 139 private final String localPart; 140 141 /** 142 * <p>prefix of this <code>QName</code>.</p> 143 */ 144 private final String prefix; 145 146 /** 147 * <p><code>QName</code> constructor specifying the Namespace URI 148 * and local part.</p> 149 * 150 * <p>If the Namespace URI is <code>null</code>, it is set to 151 * {@link javax.xml.XMLConstants#NULL_NS_URI 152 * XMLConstants.NULL_NS_URI}. This value represents no 153 * explicitly defined Namespace as defined by the <a 154 * href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces 155 * in XML</a> specification. This action preserves compatible 156 * behavior with QName 1.0. Explicitly providing the {@link 157 * javax.xml.XMLConstants#NULL_NS_URI 158 * XMLConstants.NULL_NS_URI} value is the preferred coding 159 * style.</p> 160 * 161 * <p>If the local part is <code>null</code> an 162 * <code>IllegalArgumentException</code> is thrown. 163 * A local part of "" is allowed to preserve 164 * compatible behavior with QName 1.0. </p> 165 * 166 * <p>When using this constructor, the prefix is set to {@link 167 * javax.xml.XMLConstants#DEFAULT_NS_PREFIX 168 * XMLConstants.DEFAULT_NS_PREFIX}.</p> 169 * 170 * <p>The Namespace URI is not validated as a 171 * <a href="http://www.ietf.org/rfc/rfc2396.txt">URI reference</a>. 172 * The local part is not validated as a 173 * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a> 174 * as specified in <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces 175 * in XML</a>.</p> 176 * 177 * @param namespaceURI Namespace URI of the <code>QName</code> 178 * @param localPart local part of the <code>QName</code> 179 * 180 * @throws IllegalArgumentException When <code>localPart</code> is 181 * <code>null</code> 182 * 183 * @see #QName(String namespaceURI, String localPart, String 184 * prefix) QName(String namespaceURI, String localPart, String 185 * prefix) 186 */ 187 public QName(final String namespaceURI, final String localPart) { 188 this(namespaceURI, localPart, XMLConstants.DEFAULT_NS_PREFIX); 189 } 190 191 /** 192 * <p><code>QName</code> constructor specifying the Namespace URI, 193 * local part and prefix.</p> 194 * 195 * <p>If the Namespace URI is <code>null</code>, it is set to 196 * {@link javax.xml.XMLConstants#NULL_NS_URI 197 * XMLConstants.NULL_NS_URI}. This value represents no 198 * explicitly defined Namespace as defined by the <a 199 * href="http://www.w3.org/TR/REC-xml-names/#ns-qualnames">Namespaces 200 * in XML</a> specification. This action preserves compatible 201 * behavior with QName 1.0. Explicitly providing the {@link 202 * javax.xml.XMLConstants#NULL_NS_URI 203 * XMLConstants.NULL_NS_URI} value is the preferred coding 204 * style.</p> 205 * 206 * <p>If the local part is <code>null</code> an 207 * <code>IllegalArgumentException</code> is thrown. 208 * A local part of "" is allowed to preserve 209 * compatible behavior with QName 1.0. </p> 210 * 211 * <p>If the prefix is <code>null</code>, an 212 * <code>IllegalArgumentException</code> is thrown. Use {@link 213 * javax.xml.XMLConstants#DEFAULT_NS_PREFIX 214 * XMLConstants.DEFAULT_NS_PREFIX} to explicitly indicate that no 215 * prefix is present or the prefix is not relevant.</p> 216 * 217 * <p>The Namespace URI is not validated as a 218 * <a href="http://www.ietf.org/rfc/rfc2396.txt">URI reference</a>. 219 * The local part and prefix are not validated as a 220 * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a> 221 * as specified in <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces 222 * in XML</a>.</p> 223 * 224 * @param namespaceURI Namespace URI of the <code>QName</code> 225 * @param localPart local part of the <code>QName</code> 226 * @param prefix prefix of the <code>QName</code> 227 * 228 * @throws IllegalArgumentException When <code>localPart</code> 229 * or <code>prefix</code> is <code>null</code> 230 */ 231 public QName(String namespaceURI, String localPart, String prefix) { 232 233 // map null Namespace URI to default 234 // to preserve compatibility with QName 1.0 235 if (namespaceURI == null) { 236 this.namespaceURI = XMLConstants.NULL_NS_URI; 237 } else { 238 this.namespaceURI = namespaceURI; 239 } 240 241 // local part is required. 242 // "" is allowed to preserve compatibility with QName 1.0 243 if (localPart == null) { 244 throw new IllegalArgumentException( 245 "local part cannot be \"null\" when creating a QName"); 246 } 247 this.localPart = localPart; 248 249 // prefix is required 250 if (prefix == null) { 251 throw new IllegalArgumentException( 252 "prefix cannot be \"null\" when creating a QName"); 253 } 254 this.prefix = prefix; 255 } 256 257 /** 258 * <p><code>QName</code> constructor specifying the local part.</p> 259 * 260 * <p>If the local part is <code>null</code> an 261 * <code>IllegalArgumentException</code> is thrown. 262 * A local part of "" is allowed to preserve 263 * compatible behavior with QName 1.0. </p> 264 * 265 * <p>When using this constructor, the Namespace URI is set to 266 * {@link javax.xml.XMLConstants#NULL_NS_URI 267 * XMLConstants.NULL_NS_URI} and the prefix is set to {@link 268 * javax.xml.XMLConstants#DEFAULT_NS_PREFIX 269 * XMLConstants.DEFAULT_NS_PREFIX}.</p> 270 * 271 * <p><em>In an XML context, all Element and Attribute names exist 272 * in the context of a Namespace. Making this explicit during the 273 * construction of a <code>QName</code> helps prevent hard to 274 * diagnosis XML validity errors. The constructors {@link 275 * #QName(String namespaceURI, String localPart) QName(String 276 * namespaceURI, String localPart)} and 277 * {@link #QName(String namespaceURI, String localPart, String prefix)} 278 * are preferred.</em></p> 279 * 280 * <p>The local part is not validated as a 281 * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a> 282 * as specified in <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces 283 * in XML</a>.</p> 284 * 285 * @param localPart local part of the <code>QName</code> 286 * 287 * @throws IllegalArgumentException When <code>localPart</code> is 288 * <code>null</code> 289 * 290 * @see #QName(String namespaceURI, String localPart) QName(String 291 * namespaceURI, String localPart) 292 * @see #QName(String namespaceURI, String localPart, String 293 * prefix) QName(String namespaceURI, String localPart, String 294 * prefix) 295 */ 296 public QName(String localPart) { 297 this( 298 XMLConstants.NULL_NS_URI, 299 localPart, 300 XMLConstants.DEFAULT_NS_PREFIX); 301 } 302 303 /** 304 * <p>Get the Namespace URI of this <code>QName</code>.</p> 305 * 306 * @return Namespace URI of this <code>QName</code> 307 */ 308 public String getNamespaceURI() { 309 return namespaceURI; 310 } 311 312 /** 313 * <p>Get the local part of this <code>QName</code>.</p> 314 * 315 * @return local part of this <code>QName</code> 316 */ 317 public String getLocalPart() { 318 return localPart; 319 } 320 321 /** 322 * <p>Get the prefix of this <code>QName</code>.</p> 323 * 324 * <p>The prefix assigned to a <code>QName</code> might 325 * <strong><em>NOT</em></strong> be valid in a different 326 * context. For example, a <code>QName</code> may be assigned a 327 * prefix in the context of parsing a document but that prefix may 328 * be invalid in the context of a different document.</p> 329 * 330 * @return prefix of this <code>QName</code> 331 */ 332 public String getPrefix() { 333 return prefix; 334 } 335 336 /** 337 * <p>Test this <code>QName</code> for equality with another 338 * <code>Object</code>.</p> 339 * 340 * <p>If the <code>Object</code> to be tested is not a 341 * <code>QName</code> or is <code>null</code>, then this method 342 * returns <code>false</code>.</p> 343 * 344 * <p>Two <code>QName</code>s are considered equal if and only if 345 * both the Namespace URI and local part are equal. This method 346 * uses <code>String.equals()</code> to check equality of the 347 * Namespace URI and local part. The prefix is 348 * <strong><em>NOT</em></strong> used to determine equality.</p> 349 * 350 * <p>This method satisfies the general contract of {@link 351 * java.lang.Object#equals(Object) Object.equals(Object)}</p> 352 * 353 * @param objectToTest the <code>Object</code> to test for 354 * equality with this <code>QName</code> 355 * @return <code>true</code> if the given <code>Object</code> is 356 * equal to this <code>QName</code> else <code>false</code> 357 */ 358 public final boolean equals(Object objectToTest) { 359 if (objectToTest == this) { 360 return true; 361 } 362 363 if (objectToTest == null || !(objectToTest instanceof QName)) { 364 return false; 365 } 366 367 QName qName = (QName) objectToTest; 368 369 return localPart.equals(qName.localPart) 370 && namespaceURI.equals(qName.namespaceURI); 371 } 372 373 /** 374 * <p>Generate the hash code for this <code>QName</code>.</p> 375 * 376 * <p>The hash code is calculated using both the Namespace URI and 377 * the local part of the <code>QName</code>. The prefix is 378 * <strong><em>NOT</em></strong> used to calculate the hash 379 * code.</p> 380 * 381 * <p>This method satisfies the general contract of {@link 382 * java.lang.Object#hashCode() Object.hashCode()}.</p> 383 * 384 * @return hash code for this <code>QName</code> <code>Object</code> 385 */ 386 public final int hashCode() { 387 return namespaceURI.hashCode() ^ localPart.hashCode(); 388 } 389 390 /** 391 * <p><code>String</code> representation of this 392 * <code>QName</code>.</p> 393 * 394 * <p>The commonly accepted way of representing a <code>QName</code> 395 * as a <code>String</code> was 396 * <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 399 * javax.xml.transform.Transformer#setParameter(String name, Object value)}. 400 * This implementation represents a <code>QName</code> as: 401 * "{" + Namespace URI + "}" + local part. If the Namespace URI 402 * <code>.equals(XMLConstants.NULL_NS_URI)</code>, only the 403 * local part is returned. An appropriate use of this method is 404 * for debugging or logging for human consumption.</p> 405 * 406 * <p>Note the prefix value is <strong><em>NOT</em></strong> 407 * returned as part of the <code>String</code> representation.</p> 408 * 409 * <p>This method satisfies the general contract of {@link 410 * java.lang.Object#toString() Object.toString()}.</p> 411 * 412 * @return <code>String</code> representation of this <code>QName</code> 413 */ 414 public String toString() { 415 if (namespaceURI.equals(XMLConstants.NULL_NS_URI)) { 416 return localPart; 417 } else { 418 return "{" + namespaceURI + "}" + localPart; 419 } 420 } 421 422 /** 423 * <p><code>QName</code> derived from parsing the formatted 424 * <code>String</code>.</p> 425 * 426 * <p>If the <code>String</code> is <code>null</code> or does not conform to 427 * {@link #toString() QName.toString()} formatting, an 428 * <code>IllegalArgumentException</code> is thrown.</p> 429 * 430 * <p><em>The <code>String</code> <strong>MUST</strong> be in the 431 * form returned by {@link #toString() QName.toString()}.</em></p> 432 * 433 * <p>The commonly accepted way of representing a <code>QName</code> 434 * as a <code>String</code> was 435 * <a href="http://jclark.com/xml/xmlns.htm">defined</a> 436 * by James Clark. Although this is not a <em>standard</em> 437 * specification, it is in common use, e.g. {@link 438 * javax.xml.transform.Transformer#setParameter(String name, Object value)}. 439 * This implementation parses a <code>String</code> formatted 440 * as: "{" + Namespace URI + "}" + local part. If the Namespace 441 * URI <code>.equals(XMLConstants.NULL_NS_URI)</code>, only the 442 * local part should be provided.</p> 443 * 444 * <p>The prefix value <strong><em>CANNOT</em></strong> be 445 * represented in the <code>String</code> and will be set to 446 * {@link javax.xml.XMLConstants#DEFAULT_NS_PREFIX 447 * XMLConstants.DEFAULT_NS_PREFIX}.</p> 448 * 449 * <p>This method does not do full validation of the resulting 450 * <code>QName</code>. 451 * <p>The Namespace URI is not validated as a 452 * <a href="http://www.ietf.org/rfc/rfc2396.txt">URI reference</a>. 453 * The local part is not validated as a 454 * <a href="http://www.w3.org/TR/REC-xml-names/#NT-NCName">NCName</a> 455 * as specified in 456 * <a href="http://www.w3.org/TR/REC-xml-names/">Namespaces in XML</a>.</p> 457 * 458 * @param qNameAsString <code>String</code> representation 459 * of the <code>QName</code> 460 * 461 * @throws IllegalArgumentException When <code>qNameAsString</code> is 462 * <code>null</code> or malformed 463 * 464 * @return <code>QName</code> corresponding to the given <code>String</code> 465 * @see #toString() QName.toString() 466 */ 467 public static QName valueOf(String qNameAsString) { 468 469 // null is not valid 470 if (qNameAsString == null) { 471 throw new IllegalArgumentException( 472 "cannot create QName from \"null\" or \"\" String"); 473 } 474 475 // "" local part is valid to preserve compatible behavior with QName 1.0 476 if (qNameAsString.length() == 0) { 477 return new QName( 478 XMLConstants.NULL_NS_URI, 479 qNameAsString, 480 XMLConstants.DEFAULT_NS_PREFIX); 481 } 482 483 // local part only? 484 if (qNameAsString.charAt(0) != '{') { 485 return new QName( 486 XMLConstants.NULL_NS_URI, 487 qNameAsString, 488 XMLConstants.DEFAULT_NS_PREFIX); 489 } 490 491 // Namespace URI improperly specified? 492 if (qNameAsString.startsWith("{" + XMLConstants.NULL_NS_URI + "}")) { 493 throw new IllegalArgumentException( 494 "Namespace URI .equals(XMLConstants.NULL_NS_URI), " 495 + ".equals(\"" + XMLConstants.NULL_NS_URI + "\"), " 496 + "only the local part, " 497 + "\"" 498 + qNameAsString.substring(2 + XMLConstants.NULL_NS_URI.length()) 499 + "\", " 500 + "should be provided."); 501 } 502 503 // Namespace URI and local part specified 504 int endOfNamespaceURI = qNameAsString.indexOf('}'); 505 if (endOfNamespaceURI == -1) { 506 throw new IllegalArgumentException( 507 "cannot create QName from \"" 508 + qNameAsString 509 + "\", missing closing \"}\""); 510 } 511 return new QName( 512 qNameAsString.substring(1, endOfNamespaceURI), 513 qNameAsString.substring(endOfNamespaceURI + 1), 514 XMLConstants.DEFAULT_NS_PREFIX); 515 } 516 }