Class NamePool

  • All Implemented Interfaces:
    java.io.Serializable
    Direct Known Subclasses:
    DiagnosticNamePool

    public class NamePool
    extends java.lang.Object
    implements java.io.Serializable
    A NamePool holds a collection of expanded names, each containing a namespace URI, a namespace prefix, and a local name.

    Each expanded name is allocated a unique integer namecode. The namecode enables all three parts of the expanded name to be determined, that is, the prefix, the URI, and the local name.

    The equivalence betweem names depends only on the URI and the local name. The namecode is designed so that if two namecodes represent names with the same URI and local name, the two namecodes are the same in the bottom 20 bits. It is therefore possible to compare two names for equivalence by performing an integer comparison of these 20 bits. The bottom 20 bits of a namecode are referred to as a fingerprint.

    The NamePool eliminates duplicate names if they have the same prefix, uri, and local part. It retains duplicates if they have different prefixes

    Internally the NamePool is organized as a fixed number of hash chains. The selection of a hash chain is based on hashing the local name, because it is unusual to have many names that share the same local name but use different URIs. There are 1024 hash chains and the identifier of the hash chain forms the bottom ten bits of the namecode. The next ten bits represent the sequential position of an entry within the hash chain. The upper bits represent the selection of prefix, from among the list of prefixes that have been used with a given URI. A prefix part of zero means no prefix; if the two prefixes used with a particular namespace are "xs" and "xsd", say, then these will be prefix codes 1 and 2.

    Fingerprints in the range 0 to 1023 are reserved for system use, and are allocated as constants mainly to names in the XSLT and XML Schema namespaces: constants representing these names are found in StandardNames.

    Operations that update the NamePool, or that have the potential to update it, are synchronized. Read-only operations are done without synchronization. Although technically unsafe, this has not led to any problems in practice. Performance problems due to excessive contention on the NamePool have occasionally been observed: if this happens, the best strategy is to consider splitting the workload to use multiple Configurations each with a separate NamePool.

    Internal organization of the NamePool

    The NamePool holds two kinds of entry: name entries, representing expanded names (local name + prefix + URI), identified by a name code, and URI entries (prefix + URI) identified by a URI code.

    The data structure of the name table is as follows.

    There is a fixed size hash table; names are allocated to slots in this table by hashing on the local name. Each entry in the table is the head of a chain of NameEntry objects representing names that have the same hash code.

    Each NameEntry represents a distinct name (same URI and local name). It contains the local name as a string, plus a short integer representing the URI (as an offset into the array uris[] - this is known as the URIcode).

    The fingerprint of a name consists of the hash slot number (in the bottom 10 bits) concatenated with the depth of the entry down the chain of hash synonyms (in the next 10 bits). Fingerprints with depth 0 (i.e., in the range 0-1023) are reserved for predefined names (names of XSLT elements and attributes, and of built-in types). These names are not stored in the name pool, but are accessible as if they were.

    A nameCode contains the fingerprint in the bottom 20 bits. It also contains a 10-bit prefix index. This distinguishes the prefix used, among all the prefixes that have been used with this namespace URI. If the prefix index is zero, the prefix is null. Otherwise, it indexes an array of prefix Strings associated with the namespace URI. Note that the data structures and algorithms are optimized for the case where URIs usually use the same prefix.

    The nameCode -1 is reserved to mean "not known" or inapplicable. The fingerprint -1 has the same meaning. Note that masking the nameCode -1 to extract its bottom 20 bits is incorrect, and will lead to errors.

    Modified in 9.4 to remove namespace codes.

    Author:
    Michael H. Kay
    See Also:
    Serialized Form
    • Nested Class Summary

      Nested Classes 
      Modifier and Type Class Description
      static class  NamePool.NamePoolLimitException
      Uncaught Exception raised when some limit in the design of the name pool is exceeded
    • Field Summary

      Fields 
      Modifier and Type Field Description
      static int FP_MASK
      FP_MASK is a mask used to obtain a fingerprint from a nameCode.
      static int MAX_PREFIXES_PER_URI  
      (package private) short urisUsed
      Number of entries used in the uris and prefixesForUri arrays
      static int USER_DEFINED_MASK  
    • Constructor Summary

      Constructors 
      Constructor Description
      NamePool()
      Create a NamePool
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      int allocate​(java.lang.String prefix, java.lang.String uri, java.lang.String localName)
      Allocate a name from the pool, or a new Name if there is not a matching one there
      int allocateClarkName​(java.lang.String expandedName)
      Allocate a fingerprint given a Clark Name
      short allocateCodeForURI​(java.lang.String uri)
      Allocate the uri code for a given URI; create one if not found
      int allocateLexicalQName​(java.lang.CharSequence qname, boolean useDefault, NamespaceResolver resolver, NameChecker checker)
      Get the nameCode for a lexical QName, given a namespace resolver.
      void diagnosticDump()
      Diagnostic print of the namepool contents.
      java.lang.String getClarkName​(int nameCode)
      Get the Clark form of a name, given its name code or fingerprint
      java.lang.Object getClientData​(java.lang.Class key)
      Retrieve client data on behalf of a user of the namepool
      short getCodeForURI​(java.lang.String uri)
      Get the uri code for a given URI
      java.lang.String getDisplayName​(int nameCode)
      Get the display form of a name (the QName), given its name code or fingerprint
      java.lang.String getEQName​(int nameCode)
      Get the EQName form of a name, given its name code or fingerprint
      int getFingerprint​(java.lang.String uri, java.lang.String localName)
      Get a fingerprint for the name with a given uri and local name.
      java.lang.String getLocalName​(int nameCode)
      Get the local part of a name, given its name code or fingerprint
      NamespaceBinding getNamespaceBinding​(int namecode)
      Get a namespace binding for a given namecode.
      java.lang.String getPrefix​(int nameCode)
      Get the prefix part of a name, given its name code
      StructuredQName getStructuredQName​(int namecode)
      Get a namespace binding for a given namecode.
      java.lang.String getURI​(int nameCode)
      Get the namespace-URI of a name, given its name code or fingerprint
      short getURICode​(int nameCode)
      Get the URI code of a name, given its name code or fingerprint
      java.lang.String getURIFromURICode​(short code)
      Get the namespace URI from a URI code.
      static boolean isPrefixed​(int nameCode)
      Determine whether a given namecode has a non-empty prefix (and therefore, in the case of attributes, whether the name is in a non-null namespace
      static java.lang.String[] parseClarkName​(java.lang.String expandedName)
      Parse a Clark-format expanded name, returning the URI and local name
      void setClientData​(java.lang.Class key, java.lang.Object value)
      Save client data on behalf of a user of the namepool
      void statistics()
      Statistics summarizing the namepool contents.
      java.lang.String suggestPrefixForURI​(java.lang.String URI)
      Suggest a prefix for a given URI.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Field Detail

      • FP_MASK

        public static final int FP_MASK
        FP_MASK is a mask used to obtain a fingerprint from a nameCode. Given a nameCode nc, the fingerprint is nc & NamePool.FP_MASK. (In practice, Saxon code often uses the literal constant 0xfffff, to extract the bottom 20 bits).

        The difference between a fingerprint and a nameCode is that a nameCode contains information about the prefix of a name, the fingerprint depends only on the namespace URI and local name. Note that the "null" nameCode (-1) does not produce the "null" fingerprint (also -1) when this mask is applied.

        See Also:
        Constant Field Values
      • urisUsed

        short urisUsed
        Number of entries used in the uris and prefixesForUri arrays
    • Constructor Detail

      • NamePool

        public NamePool()
        Create a NamePool
    • Method Detail

      • getNamespaceBinding

        public NamespaceBinding getNamespaceBinding​(int namecode)
        Get a namespace binding for a given namecode.
        Parameters:
        namecode - a code identifying an expanded QName, e.g. of an element or attribute
        Returns:
        an object identifying the namespace binding used in the given name. The namespace binding identifies both the prefix and the URI.
      • getStructuredQName

        public StructuredQName getStructuredQName​(int namecode)
        Get a namespace binding for a given namecode.
        Parameters:
        namecode - a code identifying an expanded QName, e.g. of an element or attribute
        Returns:
        an object identifying the namespace binding used in the given name. The namespace binding identifies both the prefix and the URI.
      • isPrefixed

        public static boolean isPrefixed​(int nameCode)
        Determine whether a given namecode has a non-empty prefix (and therefore, in the case of attributes, whether the name is in a non-null namespace
        Parameters:
        nameCode - the name code to be tested
        Returns:
        true if the name has a non-empty prefix
      • allocateCodeForURI

        public short allocateCodeForURI​(java.lang.String uri)
        Allocate the uri code for a given URI; create one if not found
        Parameters:
        uri - The namespace URI. Supply "" or null for the "null namespace"
        Returns:
        an integer code that uniquely identifies this URI within the namepool.
      • getCodeForURI

        public short getCodeForURI​(java.lang.String uri)
        Get the uri code for a given URI
        Parameters:
        uri - the URI whose code is required
        Returns:
        the associated integer URI code, or -1 if not present in the name pool
      • suggestPrefixForURI

        public java.lang.String suggestPrefixForURI​(java.lang.String URI)
        Suggest a prefix for a given URI. If there are several, it's undefined which one is returned. If there are no prefixes registered for this URI, return null.
        Parameters:
        URI - the namespace URI
        Returns:
        a prefix that has previously been associated with this URI, if available; otherwise null
      • allocate

        public int allocate​(java.lang.String prefix,
                            java.lang.String uri,
                            java.lang.String localName)
        Allocate a name from the pool, or a new Name if there is not a matching one there
        Parameters:
        prefix - the namespace prefix. Use "" for the null prefix, representing the absent namespace
        uri - the namespace URI. Use "" or null for the non-namespace.
        localName - the local part of the name
        Returns:
        an integer (the "namecode") identifying the name within the namepool. The Name itself may be retrieved using the getName(int) method
      • getURI

        public java.lang.String getURI​(int nameCode)
        Get the namespace-URI of a name, given its name code or fingerprint
        Parameters:
        nameCode - the name code or fingerprint of a name
        Returns:
        the namespace URI corresponding to this name code. Returns "" for the no-namespace.
        Throws:
        java.lang.IllegalArgumentException - if the nameCode is not known to the NamePool.
      • getURICode

        public short getURICode​(int nameCode)
        Get the URI code of a name, given its name code or fingerprint
        Parameters:
        nameCode - the name code or fingerprint of a name in the name pool
        Returns:
        the integer code identifying the namespace URI part of the name
      • getLocalName

        public java.lang.String getLocalName​(int nameCode)
        Get the local part of a name, given its name code or fingerprint
        Parameters:
        nameCode - the integer name code or fingerprint of the name
        Returns:
        the local part of the name represented by this name code or fingerprint
      • getPrefix

        public java.lang.String getPrefix​(int nameCode)
        Get the prefix part of a name, given its name code
        Parameters:
        nameCode - the integer name code of a name in the name pool
        Returns:
        the prefix of this name. Note that if a fingerprint rather than a full name code is supplied the returned prefix will be ""
      • getDisplayName

        public java.lang.String getDisplayName​(int nameCode)
        Get the display form of a name (the QName), given its name code or fingerprint
        Parameters:
        nameCode - the integer name code or fingerprint of a name in the name pool
        Returns:
        the corresponding lexical QName (if a fingerprint was supplied, this will simply be the local name)
      • getClarkName

        public java.lang.String getClarkName​(int nameCode)
        Get the Clark form of a name, given its name code or fingerprint
        Parameters:
        nameCode - the integer name code or fingerprint of a name in the name pool
        Returns:
        the local name if the name is in the null namespace, or "{uri}local" otherwise. The name is always interned.
      • getEQName

        public java.lang.String getEQName​(int nameCode)
        Get the EQName form of a name, given its name code or fingerprint
        Parameters:
        nameCode - the integer name code or fingerprint of a name in the name pool
        Returns:
        the name in the form '':local for a name in no namespace, or 'uri':local for a name in a namespace
      • allocateClarkName

        public int allocateClarkName​(java.lang.String expandedName)
        Allocate a fingerprint given a Clark Name
        Parameters:
        expandedName - the name in Clark notation, that is "localname" or "{uri}localName"
        Returns:
        the fingerprint of the name, which need not previously exist in the name pool
      • parseClarkName

        public static java.lang.String[] parseClarkName​(java.lang.String expandedName)
        Parse a Clark-format expanded name, returning the URI and local name
        Parameters:
        expandedName - the name in Clark notation, that is "localname" or "{uri}localName"
        Returns:
        an array of two strings, the URI and the local name respectively
      • getFingerprint

        public int getFingerprint​(java.lang.String uri,
                                  java.lang.String localName)
        Get a fingerprint for the name with a given uri and local name. These must be present in the NamePool. The fingerprint has the property that if two fingerprint are the same, the names are the same (ie. same local name and same URI).
        Parameters:
        uri - the namespace URI of the required QName
        localName - the local part of the required QName
        Returns:
        the integer fingerprint, or -1 if this is not found in the name pool
      • getURIFromURICode

        public java.lang.String getURIFromURICode​(short code)
        Get the namespace URI from a URI code.
        Parameters:
        code - a code that identifies the URI within the name pool
        Returns:
        the URI represented by this code
      • allocateLexicalQName

        public int allocateLexicalQName​(java.lang.CharSequence qname,
                                        boolean useDefault,
                                        NamespaceResolver resolver,
                                        NameChecker checker)
                                 throws XPathException
        Get the nameCode for a lexical QName, given a namespace resolver.
        Parameters:
        qname - the lexical QName (with leading and trailing whitespace allowed).
        useDefault - if true, an absent prefix is resolved by the NamespaceResolver to the namespace URI assigned to the prefix "". If false, an absent prefix is interpreted as meaning the name is in no namespace.
        resolver - NamespaceResolver used to resolve the namespace prefix to a namespace URI
        checker - NameChecker used to check names against the XML 1.0 or 1.1 specification
        Returns:
        the corresponding nameCode
        Throws:
        XPathException - if the string is not a valid lexical QName or if the namespace prefix has not been declared
      • setClientData

        public void setClientData​(java.lang.Class key,
                                  java.lang.Object value)
        Save client data on behalf of a user of the namepool
        Parameters:
        key - the class that is maintaining private data in the name pool
        value - the private data maintained in the name pool on behalf of this class
      • getClientData

        public java.lang.Object getClientData​(java.lang.Class key)
        Retrieve client data on behalf of a user of the namepool
        Parameters:
        key - the class that is maintaining private data in the name pool
        Returns:
        the private data maintained in the name pool on behalf of this class
      • diagnosticDump

        public void diagnosticDump()
        Diagnostic print of the namepool contents.
      • statistics

        public void statistics()
        Statistics summarizing the namepool contents. This method outputs summary statistical information to System.err