Home | History | Annotate | Download | only in namespace
      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 (at) 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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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