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