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.
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
prefix
- the namespace prefix. Use "" for the null prefix, representing the absent namespaceuri
- the namespace URI. Use "" or null for the non-namespace.localName
- the local part of the name
- 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
prefix
- - the namespace prefixuriCode
- - the code of the URIlocalName
- - the local part of the QName
- an integer (the "namecode") identifying the name within the namepool.
allocateClarkName
public int allocateClarkName(String expandedName)
Allocate a fingerprint given a Clark Name
expandedName
- the name in Clark notation, that is "localname" or "{uri}localName"
- the fingerprint of the name, which need not previously exist in the name pool
allocateCodeForURI
public short allocateCodeForURI(String uri)
Allocate the uri code for a given URI; create one if not found
uri
- The namespace URI. Supply "" or null for the "null namespace"
- an integer code that uniquely identifies this URI within the namepool.
allocateLexicalQName
public int allocateLexicalQName(CharSequence qname,
boolean useDefault,
NamespaceResolver resolver,
NameChecker checker)
throws XPathException
Get the nameCode for a lexical QName, given a namespace resolver.
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 URIchecker
- NameChecker used to check names against the XML 1.0 or 1.1 specification
- the corresponding nameCode
XPathException
- if the string is not a valid lexical QName or
if the namespace prefix has not been declared
allocateNamespaceCode
public int allocateNamespaceCode(String prefix,
String uri)
Allocate the namespace code for a namespace prefix/URI pair.
Create it if not already present
prefix
- the namespace prefixuri
- the namespace URI
- an integer code identifying the namespace. The namespace code
identifies both the prefix and the URI.
allocateNamespaceCode
public int allocateNamespaceCode(int namecode)
Allocate a namespace code for the prefix/URI of a given namecode
namecode
- a code identifying an expanded QName, e.g. of an element or attribute
- a code identifying the namespace used in the given name. The namespace code
identifies both the prefix and the URI.
diagnosticDump
public void diagnosticDump()
Diagnostic print of the namepool contents.
getClarkName
public String getClarkName(int nameCode)
Get the Clark form of a name, given its name code or fingerprint
nameCode
- the integer name code or fingerprint of a name in the name pool
- the local name if the name is in the null namespace, or "{uri}local"
otherwise. The name is always interned.
getClientData
public Object getClientData(Class key)
Retrieve client data on behalf of a user of the namepool
key
- the class that is maintaining private data in the name pool
- the private data maintained in the name pool on behalf of this class
getCodeForPrefix
public short getCodeForPrefix(String prefix)
Get the prefix code for a given Prefix
prefix
- the prefix. Supply "" for the null prefix representing the default namespace.
- a code uniquely identifying this prefix within the name pool, or -1 if not found
getCodeForURI
public short getCodeForURI(String uri)
Get the uri code for a given URI
uri
- the URI whose code is required
- the associated integer URI code, or -1 if not present in the name pool
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.
- a singular NamePool, shared by all users of this Java VM instance.
getDisplayName
public String getDisplayName(int nameCode)
Get the display form of a name (the QName), given its name code or fingerprint
nameCode
- the integer name code or fingerprint of a name in the name pool
- the corresponding lexical QName (if a fingerprint was supplied, this will
simply be the 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).
uri
- the namespace URI of the required QNamelocalName
- the local part of the required QName
- the integer fingerprint, or -1 if this is not found in the name pool
getLocalName
public String getLocalName(int nameCode)
Get the local part of a name, given its name code or fingerprint
nameCode
- the integer name code or fingerprint of the name
- the local part of the name represented by this name code or fingerprint
getNamespaceCode
public int getNamespaceCode(String prefix,
String uri)
Get the existing namespace code for a namespace prefix/URI pair.
prefix
- the namespace prefix. May be "" for the default namespaceuri
- the namespace URI. May be "" for the "null namespace"
- the integer namespace code that identifies this namespace binding;
or -1 if this binding is not present in the name pool
getNamespaceCode
public int getNamespaceCode(int namecode)
Allocate a namespace code for a given namecode
namecode
- a code identifying an expanded QName, e.g. of an element or attribute
- 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).
getPrefix
public String getPrefix(int nameCode)
Get the prefix part of a name, given its name code
nameCode
- the integer name code of a name in the name pool
- the prefix of this name. Note that if a fingerprint rather than a full name code is supplied
the returned prefix will be ""
getPrefixFromNamespaceCode
public String getPrefixFromNamespaceCode(int code)
Get the namespace prefix from a namespace code.
code
- a namespace code representing the binding of a prefix to a URI)
- the prefix represented by this namespace binding
getPrefixIndex
public static int getPrefixIndex(int nameCode)
Get the prefix index from a namecode
- 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)
getURI
public String getURI(int nameCode)
Get the namespace-URI of a name, given its name code or fingerprint
nameCode
- the name code or fingerprint of a name
- the namespace URI corresponding to this name code. Returns "" for the
null namespace.
getURICode
public short getURICode(int nameCode)
Get the URI code of a name, given its name code or fingerprint
nameCode
- the name code or fingerprint of a name in the name pool
- the integer code identifying the namespace URI part of the name
getURIFromNamespaceCode
public String getURIFromNamespaceCode(int code)
Get the namespace URI from a namespace code.
code
- a namespace code, representing the binding of a prefix to a namespace URI
- the namespace URI represented by this namespace binding
getURIFromURICode
public String getURIFromURICode(short code)
Get the namespace URI from a URI code.
code
- a code that identifies the URI within the name pool
- the URI represented by this code
parseClarkName
public static String[] parseClarkName(String expandedName)
Parse a Clark-format expanded name, returning the URI and local name
expandedName
- the name in Clark notation, that is "localname" or "{uri}localName"
- an array of two strings, the URI and the local name respectively
setClientData
public void setClientData(Class key,
Object value)
Save client data on behalf of a user of the namepool
key
- the class that is maintaining private data in the name poolvalue
- the private data maintained in the name pool on behalf of this class
setDefaultNamePool
public static void setDefaultNamePool(NamePool pool)
Set the default NamePool. NOTE: although a "default" namepool still exists, it is actually
no longer used by default. Since Saxon 8.9, when you create a new Configuration, a new NamePool
specific to that configuration is created. The so-called "default" namepool is only used if you
specifically ask for it.
statistics
public void statistics()
Statistics summarizing the namepool contents.
This method outputs summary statistical information to System.err
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.
- a prefix that has previously been associated with this URI, if available; otherwise null