001: package net.sf.saxon.functions;
002:
003: import net.sf.saxon.Controller;
004: import net.sf.saxon.type.Type;
005: import net.sf.saxon.expr.*;
006: import net.sf.saxon.om.*;
007: import net.sf.saxon.sort.DocumentOrderIterator;
008: import net.sf.saxon.sort.LocalOrderComparer;
009: import net.sf.saxon.style.StandardNames;
010: import net.sf.saxon.trans.KeyManager;
011: import net.sf.saxon.trans.XPathException;
012: import net.sf.saxon.value.AtomicValue;
013: import net.sf.saxon.value.Cardinality;
014: import net.sf.saxon.value.StringValue;
015:
016: public class Idref extends SystemFunction {
017:
018: /**
019: * Simplify: add a second implicit argument, the context document
020: */
021:
022: public Expression simplify(StaticContext env) throws XPathException {
023: Idref f = (Idref) super .simplify(env);
024: f.addContextDocumentArgument(1, "idref");
025: return f;
026: }
027:
028: public void checkArguments(StaticContext env) throws XPathException {
029: super .checkArguments(env);
030: Optimizer opt = env.getConfiguration().getOptimizer();
031: argument[0] = ExpressionTool.unsorted(opt, argument[0], false);
032: }
033:
034: /**
035: * Get the static properties of this expression (other than its type). The result is
036: * bit-signficant. These properties are used for optimizations. In general, if
037: * property bit is set, it is true, but if it is unset, the value is unknown.
038: */
039:
040: public int computeSpecialProperties() {
041: int prop = StaticProperty.ORDERED_NODESET
042: | StaticProperty.SINGLE_DOCUMENT_NODESET
043: | StaticProperty.NON_CREATIVE;
044: if ((getNumberOfArguments() == 1)
045: || (argument[1].getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0) {
046: prop |= StaticProperty.CONTEXT_DOCUMENT_NODESET;
047: }
048: return prop;
049: }
050:
051: /**
052: * preEvaluate: this method suppresses compile-time evaluation by doing nothing
053: */
054:
055: public Expression preEvaluate(StaticContext env) {
056: return this ;
057: }
058:
059: /**
060: * Enumerate the results of the expression
061: */
062:
063: public SequenceIterator iterate(XPathContext context)
064: throws XPathException {
065:
066: Controller controller = context.getController();
067:
068: NodeInfo arg2 = (NodeInfo) argument[1].evaluateItem(context);
069: if (arg2.getNodeKind() != Type.DOCUMENT) {
070: dynamicError(
071: "In the idref() function,"
072: + " the context node must be in a tree whose root is a document node",
073: context);
074: return null;
075: }
076: DocumentInfo doc = (DocumentInfo) arg2;
077:
078: int fprint = StandardNames.XS_IDREFS;
079:
080: // If the argument is a singleton, we evaluate the function
081: // directly; otherwise we recurse to evaluate it once for each Item
082: // in the sequence.
083:
084: Expression expression = argument[0];
085: if (Cardinality.allowsMany(expression.getCardinality())) {
086: IdrefMappingFunction map = new IdrefMappingFunction();
087: map.document = doc;
088: map.keyContext = context;
089:
090: SequenceIterator keys = argument[0].iterate(context);
091: SequenceIterator allValues = new MappingIterator(keys, map,
092: null);
093: return new DocumentOrderIterator(allValues,
094: LocalOrderComparer.getInstance());
095: } else {
096: AtomicValue keyValue = (AtomicValue) argument[0]
097: .evaluateItem(context);
098: if (keyValue == null) {
099: return EmptyIterator.getInstance();
100: }
101: KeyManager keyManager = controller.getKeyManager();
102: return keyManager.selectByKey(fprint, doc, keyValue,
103: context);
104:
105: }
106: }
107:
108: private static class IdrefMappingFunction implements
109: MappingFunction {
110: public DocumentInfo document;
111: public XPathContext keyContext;
112:
113: /**
114: * Implement the MappingFunction interface
115: */
116:
117: public Object map(Item item, XPathContext context)
118: throws XPathException {
119: KeyManager keyManager = keyContext.getController()
120: .getKeyManager();
121: AtomicValue keyValue;
122: if (item instanceof AtomicValue) {
123: keyValue = (AtomicValue) item;
124: } else {
125: keyValue = new StringValue(item.getStringValue());
126: }
127: return keyManager.selectByKey(StandardNames.XS_IDREFS,
128: document, keyValue, keyContext);
129:
130: }
131: }
132:
133: }
134:
135: //
136: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
137: // you may not use this file except in compliance with the License. You may obtain a copy of the
138: // License at http://www.mozilla.org/MPL/
139: //
140: // Software distributed under the License is distributed on an "AS IS" basis,
141: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
142: // See the License for the specific language governing rights and limitations under the License.
143: //
144: // The Original Code is: all this file.
145: //
146: // The Initial Developer of the Original Code is Michael H. Kay.
147: //
148: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
149: //
150: // Contributor(s): none.
151: //
|