/** Enumerate the results of the expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { Controller controller = context.getController(); Item arg2; try { arg2 = argument[2].evaluateItem(context); } catch (XPathException e) { if ("XPDY0002".equals(e.getErrorCodeLocalPart())) { dynamicError( "Cannot call the key() function when there is no context item", "XTDE1270", context); return null; } else if ("XPDY0050".equals(e.getErrorCodeLocalPart())) { dynamicError( "In the key() function," + " the node supplied in the third argument (or the context node if absent)" + " must be in a tree whose root is a document node", "XTDE1270", context); return null; } else if ("XPTY0020".equals(e.getErrorCodeLocalPart())) { dynamicError( "Cannot call the key() function when the context item is an atomic value", "XTDE1270", context); return null; } throw e; } NodeInfo origin = (NodeInfo) arg2; NodeInfo root = origin.getRoot(); if (root.getNodeKind() != Type.DOCUMENT) { dynamicError( "In the key() function," + " the node supplied in the third argument (or the context node if absent)" + " must be in a tree whose root is a document node", "XTDE1270", context); return null; } DocumentInfo doc = (DocumentInfo) root; int fprint = keyFingerprint; if (fprint == -1) { String givenkeyname = argument[0].evaluateItem(context).getStringValue(); try { fprint = controller .getNamePool() .allocateLexicalQName( givenkeyname, false, nsContext, controller.getConfiguration().getNameChecker()) & NamePool.FP_MASK; } catch (XPathException err) { dynamicError("Invalid key name: " + err.getMessage(), "XTDE1260", context); } if (fprint == -1) { dynamicError("Key '" + givenkeyname + "' has not been defined", "XTDE1260", context); return null; } } // if (internal) { // System.err.println("Using key " + fprint + " on doc " + doc); // } // If the second argument is a singleton, we evaluate the function // directly; otherwise we recurse to evaluate it once for each Item // in the sequence. Expression expression = argument[1]; SequenceIterator allResults; if (Cardinality.allowsMany(expression.getCardinality())) { final XPathContext keyContext = context; final DocumentInfo document = doc; final KeyManager keyManager = controller.getKeyManager(); MappingFunction map = new MappingFunction() { // Map a value to the sequence of nodes having that value as a key value public Object map(Item item) throws XPathException { return keyManager.selectByKey( keyFingerprint, document, (AtomicValue) item, keyContext); } }; SequenceIterator keys = argument[1].iterate(context); SequenceIterator allValues = new MappingIterator(keys, map); allResults = new DocumentOrderIterator(allValues, LocalOrderComparer.getInstance()); } else { try { AtomicValue keyValue = (AtomicValue) argument[1].evaluateItem(context); if (keyValue == null) { return EmptyIterator.getInstance(); } KeyManager keyManager = controller.getKeyManager(); allResults = keyManager.selectByKey(fprint, doc, keyValue, context); } catch (XPathException e) { if (e.getLocator() == null) { e.setLocator(this); } throw e; } } if (origin == doc) { return allResults; } SubtreeFilter filter = new SubtreeFilter(); filter.origin = origin; return new ItemMappingIterator(allResults, filter); }