net.sf.saxon.trans
Class KeyManager

Object
  extended by KeyManager
All Implemented Interfaces:
Serializable
Direct Known Subclasses:
LazyKeyManager

public class KeyManager
extends Object
implements Serializable

MCH: Hacked to make certain members public, to allow for LazyKeyManager to get the access it needs to the key list, and to be able to override certain methods. KeyManager manages the set of key definitions in a stylesheet, and the indexes associated with these key definitions. It handles xsl:sort-key as well as xsl:key definitions.

The memory management in this class is subtle, with extensive use of weak references. The idea is that an index should continue to exist in memory so long as both the compiled stylesheet and the source document exist in memory: if either is removed, the index should go too. The document itself holds no reference to the index. The compiled stylesheet (which owns the KeyManager) holds a weak reference to the index. The index, of course, holds strong references to the nodes in the document. The Controller holds a strong reference to the list of indexes used for each document, so that indexes remain in memory for the duration of a transformation even if the documents themselves are garbage collected.

Potentially there is a need for more than one index for a given key name, depending on the primitive type of the value provided to the key() function. An index is built corresponding to the type of the requested value; if subsequently the key() function is called with the same name and a different type of value, then a new index is built.

For XSLT-defined keys, equality matching follows the rules of the eq operator, which means that untypedAtomic values are treated as strings. In backwards compatibility mode, all values are converted to strings.

This class is also used for internal indexes constructed (a) to support the idref() function, and (b) (in Saxon-SA only) to support filter expressions of the form /a/b/c[d=e], where the path expression being filtered must be a single-document context-free path rooted at a document node, where exactly one of d and e must be dependent on the focus, and where certain other conditions apply such as the filter predicate not being positional. The operator in this case may be either "=" or "eq". If it is "eq", then the semantics are very similar to xsl:key indexes, except that use of non-comparable types gives an error rather than a non-match. If the operator is "=", however, then the rules for handling untypedAtomic values are different: these must be converted to the type of the other operand. In this situation the following rules apply. Assume that the predicate is [use=value], where use is dependent on the focus (the indexed value), and value is the sought value.

Author:
Michael H. Kay
See Also:
Serialized Form

Field Summary
private  WeakHashMap docIndexes
           
 IntHashMap keyList
           
 
Constructor Summary
KeyManager(Configuration config)
          create a KeyManager and initialise variables
 
Method Summary
 void addKeyDefinition(int fingerprint, KeyDefinition keydef, Configuration config)
          Register a key definition.
 Map buildIndex(int keyNameFingerprint, BuiltInAtomicType itemType, Set foundItemTypes, DocumentInfo doc, XPathContext context)
          Build the index for a particular document for a named key
protected  void constructIndex(DocumentInfo doc, Map index, KeyDefinition keydef, BuiltInAtomicType soughtItemType, Set foundItemTypes, XPathContext context, boolean isFirst)
          Process one key definition to add entries to an index
 void explainKeys(Configuration config, PrintStream out)
          Diagnostic output explaining the keys
private static Object getCollationKey(AtomicValue value, BuiltInAtomicType itemType, StringCollator collation, Platform platform)
           
private  Object getIndex(DocumentInfo doc, int keyFingerprint, AtomicType itemType)
          Get the index associated with a particular key, a particular source document, and a particular primitive item type
 List getKeyDefinitions(int fingerprint)
          Get all the key definitions that match a particular fingerprint
private  void processKeyNode(NodeInfo curr, BuiltInAtomicType soughtItemType, Set foundItemTypes, KeyDefinition keydef, Map index, XPathContext xc, boolean isFirst)
          Process one matching node, adding entries to the index if appropriate
private  void putIndex(DocumentInfo doc, int keyFingerprint, AtomicType itemType, Object index, XPathContext context)
          Save the index associated with a particular key, a particular item type, and a particular document.
private  void registerIdrefKey(Configuration config)
          An internal key definition is used to support the idref() function.
 SequenceIterator selectByKey(int keyNameFingerprint, DocumentInfo doc, AtomicValue soughtValue, XPathContext context)
          Get the nodes with a given key value
 
Methods inherited from class Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

keyList

public IntHashMap keyList

docIndexes

private transient WeakHashMap docIndexes
Constructor Detail

KeyManager

public KeyManager(Configuration config)
create a KeyManager and initialise variables

Method Detail

registerIdrefKey

private void registerIdrefKey(Configuration config)
An internal key definition is used to support the idref() function. The key definition is equivalent to xsl:key match="element(*, xs:IDREF) | element(*, IDREFS) | attribute(*, xs:IDREF) | attribute(*, IDREFS)" use=".". This method creates this key definition.

Parameters:
config - The configuration. This is needed because the patterns that are generated need access to schema information.

addKeyDefinition

public void addKeyDefinition(int fingerprint,
                             KeyDefinition keydef,
                             Configuration config)
                      throws StaticError
Register a key definition. Note that multiple key definitions with the same name are allowed

Parameters:
fingerprint - Integer representing the name of the key
keydef - The details of the key's definition
config - The configuration
Throws:
StaticError - if this key definition is inconsistent with existing key definitions having the same name

getKeyDefinitions

public List getKeyDefinitions(int fingerprint)
Get all the key definitions that match a particular fingerprint

Parameters:
fingerprint - The fingerprint of the name of the required key
Returns:
The list of key definitions of the named key if there are any, or null otherwise. The members of the list will be instances of KeyDefinition

buildIndex

public Map buildIndex(int keyNameFingerprint,
                      BuiltInAtomicType itemType,
                      Set foundItemTypes,
                      DocumentInfo doc,
                      XPathContext context)
               throws XPathException
Build the index for a particular document for a named key

Parameters:
keyNameFingerprint - The fingerprint of the name of the required key
itemType - the type of the values to be indexed.
doc - The source document in question
context - The dynamic context
Returns:
the index in question, as a Map mapping a key value onto a ArrayList of nodes
Throws:
XPathException

constructIndex

protected void constructIndex(DocumentInfo doc,
                              Map index,
                              KeyDefinition keydef,
                              BuiltInAtomicType soughtItemType,
                              Set foundItemTypes,
                              XPathContext context,
                              boolean isFirst)
                       throws XPathException
Process one key definition to add entries to an index

Throws:
XPathException

processKeyNode

private void processKeyNode(NodeInfo curr,
                            BuiltInAtomicType soughtItemType,
                            Set foundItemTypes,
                            KeyDefinition keydef,
                            Map index,
                            XPathContext xc,
                            boolean isFirst)
                     throws XPathException
Process one matching node, adding entries to the index if appropriate

Parameters:
curr - the node being processed
soughtItemType - the primitive item type of the argument to the key() function that triggered this index to be built
keydef - the key definition
index - the index being constructed
xc - the context for evaluating expressions
isFirst - indicates whether this is the first key definition with a given key name (which means no sort of the resulting key entries is required)
Throws:
XPathException

selectByKey

public SequenceIterator selectByKey(int keyNameFingerprint,
                                    DocumentInfo doc,
                                    AtomicValue soughtValue,
                                    XPathContext context)
                             throws XPathException
Get the nodes with a given key value

Parameters:
keyNameFingerprint - The fingerprint of the name of the required key
doc - The source document in question
soughtValue - The required key value
context - The dynamic context, needed only the first time when the key is being built
Returns:
an iteration of the selected nodes, always in document order with no duplicates
Throws:
XPathException

getCollationKey

private static Object getCollationKey(AtomicValue value,
                                      BuiltInAtomicType itemType,
                                      StringCollator collation,
                                      Platform platform)

putIndex

private void putIndex(DocumentInfo doc,
                      int keyFingerprint,
                      AtomicType itemType,
                      Object index,
                      XPathContext context)
Save the index associated with a particular key, a particular item type, and a particular document. This needs to be done in such a way that the index is discarded by the garbage collector if the document is discarded. We therefore use a WeakHashMap indexed on the DocumentInfo, which returns Map giving the index for each key fingerprint. This index is itself another Map. The methods need to be synchronized because several concurrent transformations (which share the same KeyManager) may be creating indexes for the same or different documents at the same time.


getIndex

private Object getIndex(DocumentInfo doc,
                        int keyFingerprint,
                        AtomicType itemType)
Get the index associated with a particular key, a particular source document, and a particular primitive item type

Returns:
either an index (as a Map), or the String "under construction", or null

explainKeys

public void explainKeys(Configuration config,
                        PrintStream out)
Diagnostic output explaining the keys