net.sf.saxon.om
Class NamePool

java.lang.Object
  extended by net.sf.saxon.om.NamePool
All Implemented Interfaces:
Serializable

public class NamePool
extends Object
implements Serializable

A NamePool holds a collection of expanded names, each containing a namespace URI, a namespace prefix, and a local name; plus a collection of namespaces, each consisting of a prefix/URI pair.

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 namespace entries (prefix + URI) identified by a namespace 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.

Author:
Michael H. Kay
See Also:
Serialized Form

Nested Class Summary
static class NamePool.NamePoolLimitException
           
 
Field Summary
static int FP_MASK
          FP_MASK is a mask used to obtain a fingerprint from a nameCode.
static int MAX_PREFIXES_PER_URI
           
static int USER_DEFINED_MASK
           
 
Constructor Summary
NamePool()
           
 
Method Summary
 int allocate(String prefix, short uriCode, String localName)
          Allocate a name from the pool, or a new Name if there is not a matching one there
 int allocate(String prefix, String uri, String localName)
          Allocate a name from the pool, or a new Name if there is not a matching one there
 int allocateClarkName(String expandedName)
          Allocate a fingerprint given a Clark Name
 short allocateCodeForURI(String uri)
          Allocate the uri code for a given URI; create one if not found
 int allocateLexicalQName(CharSequence qname, boolean useDefault, NamespaceResolver resolver, NameChecker checker)
          Get the nameCode for a lexical QName, given a namespace resolver.
 int allocateNamespaceCode(int namecode)
          Allocate a namespace code for the prefix/URI of a given namecode
 int allocateNamespaceCode(String prefix, String uri)
          Allocate the namespace code for a namespace prefix/URI pair.
 void diagnosticDump()
          Diagnostic print of the namepool contents.
 String getClarkName(int nameCode)
          Get the Clark form of a name, given its name code or fingerprint
 Object getClientData(Class key)
          Retrieve client data on behalf of a user of the namepool
 short getCodeForPrefix(String prefix)
          Get the prefix code for a given Prefix
 short getCodeForURI(String uri)
          Get the uri code for a given URI
static NamePool getDefaultNamePool()
          Get the singular static NamePool.
 String getDisplayName(int nameCode)
          Get the display form of a name (the QName), given its name code or fingerprint
 int getFingerprint(String uri, String localName)
          Get a fingerprint for the name with a given uri and local name.
 int getFingerprintForExpandedName(String expandedName)
          Get fingerprint for expanded name supplied in Clark format: {uri}local
 String getLocalName(int nameCode)
          Get the local part of a name, given its name code or fingerprint
 int getNamespaceCode(int namecode)
          Allocate a namespace code for a given namecode
 int getNamespaceCode(String prefix, String uri)
          Get the existing namespace code for a namespace prefix/URI pair.
 String getPrefix(int nameCode)
          Get the prefix part of a name, given its name code or fingerprint
 String getPrefixFromNamespaceCode(int code)
          Get the namespace prefix from a namespace code.
static int getPrefixIndex(int nameCode)
          Get the prefix index from a namecode
 String getPrefixWithIndex(short uriCode, int index)
          Get a prefix among all the prefixes used with a given URI, given its index
 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
 String getURIFromNamespaceCode(int code)
          Get the namespace URI from a namespace code.
 String getURIFromURICode(short code)
          Get the namespace URI from a URI code.
static String[] parseClarkName(String expandedName)
          Parse a Clark-format expanded name, returning the URI and local name
 void setClientData(Class key, Object value)
          Save client data on behalf of a user of the namepool
static void setDefaultNamePool(NamePool pool)
          Set the default NamePool (used after loading a compiled stylesheet)
 void statistics()
          Statistics summarizing the namepool contents.
 String suggestPrefixForURI(String URI)
          Suggest a prefix for a given URI.
 
Methods inherited from class java.lang.Object
equals, 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

USER_DEFINED_MASK

public static final int USER_DEFINED_MASK
See Also:
Constant Field Values

MAX_PREFIXES_PER_URI

public static final int MAX_PREFIXES_PER_URI
See Also:
Constant Field Values
Constructor Detail

NamePool

public NamePool()
Method Detail

getDefaultNamePool

public static NamePool getDefaultNamePool()
Get the singular static NamePool. Until Saxon 8.9, all Configurations shared the same NamePool unless users explicitly allocated a different one. This is no longer the case (each Configuration now has its own NamePool), but the singular static NamePool remains available.

Returns:
a singular NamePool, shared by all users of this Java VM instance.

setDefaultNamePool

public static void setDefaultNamePool(NamePool pool)
Set the default NamePool (used after loading a compiled stylesheet)


allocateNamespaceCode

public int allocateNamespaceCode(String prefix,
                                 String uri)
Allocate the namespace code for a namespace prefix/URI pair. Create it if not already present

Parameters:
prefix - the namespace prefix
uri - the namespace URI
Returns:
an integer code identifying the namespace. The namespace code identifies both the prefix and the URI.

getNamespaceCode

public int getNamespaceCode(String prefix,
                            String uri)
Get the existing namespace code for a namespace prefix/URI pair.

Returns:
-1 if there is none present

getNamespaceCode

public int getNamespaceCode(int namecode)
Allocate a namespace code for a given namecode

Parameters:
namecode - a code identifying an expanded QName, e.g. of an element or attribute
Returns:
a code identifying the namespace used in the given name. The namespace code identifies both the prefix and the URI. Return -1 if no namespace code has been allocated (in this case the caller should call allocateNamespaceCode() to get one).

getPrefixIndex

public static int getPrefixIndex(int nameCode)
Get the prefix index from a namecode

Parameters:
nameCode - the name code
Returns:
the prefix index. A value of zero means the name is unprefixed (which in the case of an attribute, means that it is in the null namespace)

allocateCodeForURI

public short allocateCodeForURI(String uri)
Allocate the uri code for a given URI; create one if not found


getCodeForURI

public short getCodeForURI(String uri)
Get the uri code for a given URI

Returns:
-1 if not present in the name pool

getCodeForPrefix

public short getCodeForPrefix(String prefix)
Get the prefix code for a given Prefix

Returns:
-1 if not found

suggestPrefixForURI

public String suggestPrefixForURI(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.


getPrefixWithIndex

public String getPrefixWithIndex(short uriCode,
                                 int index)
Get a prefix among all the prefixes used with a given URI, given its index

Returns:
the prefix with the given index. If the index is 0, the prefix is always "".

allocate

public int allocate(String prefix,
                    String uri,
                    String localName)
Allocate a name from the pool, or a new Name if there is not a matching one there

Parameters:
prefix -
uri - - the namespace URI. Use "" or null for the non-namespace.
localName -
Returns:
an integer (the "namecode") identifying the name within the namepool. The Name itself may be retrieved using the getName(int) method

allocate

public int allocate(String prefix,
                    short uriCode,
                    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
uriCode - - the code of the URI
localName - - the local part of the QName
Returns:
an integer (the "namecode") identifying the name within the namepool.

allocateNamespaceCode

public int allocateNamespaceCode(int namecode)
Allocate a namespace code for the prefix/URI of a given namecode

Parameters:
namecode - a code identifying an expanded QName, e.g. of an element or attribute
Returns:
a code identifying the namespace used in the given name. The namespace code identifies both the prefix and the URI.

getURI

public String getURI(int nameCode)
Get the namespace-URI of a name, given its name code or fingerprint

Returns:
the namespace URI corresponding to this name code. Returns "" for the null namespace.
Throws:
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


getLocalName

public String getLocalName(int nameCode)
Get the local part of a name, given its name code or fingerprint


getPrefix

public String getPrefix(int nameCode)
Get the prefix part of a name, given its name code or fingerprint


getDisplayName

public String getDisplayName(int nameCode)
Get the display form of a name (the QName), given its name code or fingerprint


getClarkName

public String getClarkName(int nameCode)
Get the Clark form of a name, given its name code or fingerprint

Returns:
the local name if the name is in the null namespace, or "{uri}local" otherwise. The name is always interned.

allocateClarkName

public int allocateClarkName(String expandedName)
Allocate a fingerprint given a Clark Name


parseClarkName

public static String[] parseClarkName(String expandedName)
Parse a Clark-format expanded name, returning the URI and local name


getFingerprint

public int getFingerprint(String uri,
                          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).

Returns:
-1 if not found

getURIFromNamespaceCode

public String getURIFromNamespaceCode(int code)
Get the namespace URI from a namespace code.


getURIFromURICode

public String getURIFromURICode(short code)
Get the namespace URI from a URI code.


getPrefixFromNamespaceCode

public String getPrefixFromNamespaceCode(int code)
Get the namespace prefix from a namespace code.


allocateLexicalQName

public int allocateLexicalQName(CharSequence qname,
                                boolean useDefault,
                                NamespaceResolver resolver,
                                NameChecker checker)
                         throws DynamicError
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.
checker - NameChecker used to check names against the XML 1.0 or 1.1 specification
Returns:
the corresponding nameCode
Throws:
DynamicError - if the string is not a valid lexical QName or if the namespace prefix has not been declared*

getFingerprintForExpandedName

public int getFingerprintForExpandedName(String expandedName)
Get fingerprint for expanded name supplied in Clark format: {uri}local


setClientData

public void setClientData(Class key,
                          Object value)
Save client data on behalf of a user of the namepool


getClientData

public Object getClientData(Class key)
Retrieve client data on behalf of a user of the namepool


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



Copyright (C) Michael H. Kay. All rights reserved.