result.addAll(callback.evalFunction(null, null, params));
Sequence callbackResult = callback.evalFunction(null, null, params); for (SequenceIterator iter = callbackResult.iterate(); iter.hasNext(); ) { Item next = iter.nextItem(); if (Type.subTypeOf(next.getType(), Type.NODE)) { nodeNr = builder.getDocument().getLastNode(); try { next.copyTo(context.getBroker(), receiver); result.add(builder.getDocument().getNode(++nodeNr)); lastNodeNr = nodeNr; } catch (SAXException e) { throw new XPathException(getASTNode(), "Internal error while copying nodes: " + e.getMessage(), e); } } }
    private final Sequence processText(MemTreeBuilder builder, Sequence nodes, int width,             FunctionCall callback, FunctionCall resultCallback, Sequence extraArgs) throws XPathException {        StringBuffer str = new StringBuffer();        NodeValue node;        List offsets = null;        NodeProxy firstProxy = null;                // First step: scan the passed node sequence and collect the string values of all nodes.        // Translate the relative offsets into absolute offsets.        for (SequenceIterator i = nodes.iterate(); i.hasNext(); ) {            node = (NodeValue) i.nextItem();            if (node.getImplementationType() == NodeValue.IN_MEMORY_NODE)                throw new XPathException(getASTNode(), "Function kwic-display" +                         " can not be invoked on constructed nodes");            NodeProxy proxy = (NodeProxy) node;            // remember the first node, we need it later            if (firstProxy == null)                firstProxy = proxy;            TextImpl text = (TextImpl) proxy.getNode();                        Match next = proxy.getMatches();            while (next != null) {                if (next.getNodeId() == text.getGID()) {                    if (offsets == null)                        offsets = new ArrayList();                    int freq = next.getFrequency();                    for (int j = 0; j < freq; j++) {                        // translate the relative offset into an absolute offset and add it to the list                        Match.Offset offset = next.getOffset(j);                        offset.setOffset(str.length() + offset.getOffset());                        offsets.add(offset);                    }                }                next = next.getNextMatch();            }                        // append the string value of the node to the buffer            str.append(text.getData());        }                // Second step: output the text        ValueSequence result = new ValueSequence();        int nodeNr;        int currentWidth = 0;        if (offsets == null) {            // no matches: just output the entire text            if (width > str.length())                width = str.length();            nodeNr = builder.characters(str.substring(0, width));            result.add(builder.getDocument().getNode(nodeNr));            currentWidth += width;        } else {            // sort the offsets            FastQSort.sort(offsets, 0, offsets.size() - 1);                        int nextOffset = 0;            int pos = 0;                        // prepare array for callback function arguments            Sequence params[] = new Sequence[3];            params[1] = firstProxy;            params[2] = extraArgs;                        // handle the first match: if the text to the left of the match            // is larger than half of the width, truncate it.             if (str.length() > width) {                Match.Offset firstMatch = (Match.Offset) offsets.get(nextOffset++);                if (firstMatch.getOffset() > 0) {                    int leftWidth = (width - firstMatch.getLength()) / 2;                    if (firstMatch.getOffset() > leftWidth) {                        pos = truncateStart(str, firstMatch.getOffset() - leftWidth, firstMatch.getOffset());                        leftWidth = firstMatch.getOffset() - pos;                    } else                        leftWidth = firstMatch.getOffset();                    nodeNr = builder.characters(str.substring(pos, pos + leftWidth));                    result.add(builder.getDocument().getNode(nodeNr));                    currentWidth += leftWidth;                    pos += leftWidth;                }                    params[0] = new StringValue(str.substring(firstMatch.getOffset(), firstMatch.getOffset() + firstMatch.getLength()));                result.addAll(callback.evalFunction(null, null, params));                currentWidth += firstMatch.getLength();                pos += firstMatch.getLength();            } else                width = str.length();                        // output the rest of the text and matches            Match.Offset offset;            for (int i = nextOffset; i < offsets.size() && currentWidth < width; i++) {                offset = (Match.Offset) offsets.get(i);                if (offset.getOffset() > pos) {                    int len = offset.getOffset() - pos;                    if (currentWidth + len > width)                        len = width - currentWidth;                    nodeNr = builder.characters(str.substring(pos, pos + len));                    result.add(builder.getDocument().getNode(nodeNr));                    currentWidth += len;                    pos += len;                }                                if (currentWidth + offset.getLength() < width) {                    params[0] = new StringValue(str.substring(offset.getOffset(), offset.getOffset() + offset.getLength()));                      result.addAll(callback.evalFunction(null, null, params));                    currentWidth += offset.getLength();                    pos += offset.getLength();                } else                    break;            }            // print the final text chunk if more space is available            if (currentWidth < width && pos < str.length()) {                boolean truncated = false;                int len = str.length() - pos;                if (len > width - currentWidth) {                    truncated = true;                    len = width - currentWidth;                }                nodeNr = builder.characters(str.substring(pos, pos + len));                result.add(builder.getDocument().getNode(nodeNr));                currentWidth += len;                                if (truncated) {                    nodeNr = builder.characters(" ...");                    result.add(builder.getDocument().getNode(nodeNr));                }            }        }                if (resultCallback != null) {            Sequence params[] = new Sequence[3];            params[0] = result;            params[1] = new IntegerValue(currentWidth);            params[2] = extraArgs;            return resultCallback.evalFunction(null, null, params);        } else            return result;    }