001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.template.instruction;
018:
019: import java.util.Iterator;
020: import java.util.Stack;
021:
022: import org.apache.cocoon.components.expression.ExpressionContext;
023: import org.apache.cocoon.template.environment.ErrorHolder;
024: import org.apache.cocoon.template.environment.ExecutionContext;
025: import org.apache.cocoon.template.environment.ParsingContext;
026: import org.apache.cocoon.template.expression.JXTExpression;
027: import org.apache.cocoon.template.expression.StringTemplateParser;
028: import org.apache.cocoon.template.script.Invoker;
029: import org.apache.cocoon.template.script.event.Event;
030: import org.apache.cocoon.template.script.event.StartElement;
031: import org.apache.cocoon.xml.XMLConsumer;
032: import org.xml.sax.Attributes;
033: import org.xml.sax.Locator;
034: import org.xml.sax.SAXException;
035: import org.xml.sax.SAXParseException;
036:
037: /**
038: * @version SVN $Id: ForEach.java 449189 2006-09-23 06:52:29Z crossley $
039: */
040: public class ForEach extends Instruction {
041:
042: private final JXTExpression items;
043: private final JXTExpression var;
044: private final JXTExpression varStatus;
045: private final JXTExpression begin;
046: private final JXTExpression end;
047: private final JXTExpression step;
048:
049: public ForEach(ParsingContext parsingContext, StartElement raw,
050: Attributes attrs, Stack stack) throws SAXException {
051:
052: super (raw);
053:
054: String name = raw.getLocalName();
055: Locator locator = getLocation();
056:
057: String items = attrs.getValue("items");
058: String select = attrs.getValue("select");
059:
060: StringTemplateParser expressionCompiler = parsingContext
061: .getStringTemplateParser();
062: this .var = expressionCompiler.compileExpr(
063: attrs.getValue("var"), null, locator);
064: this .varStatus = expressionCompiler.compileExpr(attrs
065: .getValue("varStatus"), null, locator);
066: this .begin = expressionCompiler.compileInt(attrs
067: .getValue("begin"), name, locator);
068: this .end = expressionCompiler.compileInt(attrs.getValue("end"),
069: name, locator);
070: this .step = expressionCompiler.compileInt(attrs
071: .getValue("step"), name, locator);
072:
073: if (items == null) {
074: if (select == null && (begin == null || end == null)) {
075: throw new SAXParseException(
076: "forEach: \"select\", \"items\", or both \"begin\" and \"end\" must be specified",
077: locator, null);
078: }
079: } else if (select != null) {
080: throw new SAXParseException(
081: "forEach: only one of \"select\" or \"items\" may be specified",
082: locator, null);
083: }
084:
085: this .items = expressionCompiler.compileExpr(
086: items == null ? select : items, null, locator);
087: }
088:
089: public Event execute(final XMLConsumer consumer,
090: ExpressionContext expressionContext,
091: ExecutionContext executionContext,
092: MacroContext macroContext, Event startEvent, Event endEvent)
093: throws SAXException {
094: Iterator iter = null;
095: int begin, end, step;
096: String var = null, varStatus = null;
097: try {
098: iter = (this .items != null) ? this .items
099: .getIterator(expressionContext)
100: : JXTExpression.NULL_ITER;
101: begin = this .begin == null ? 0 : this .begin
102: .getIntValue(expressionContext);
103: end = this .end == null ? Integer.MAX_VALUE : this .end
104: .getIntValue(expressionContext);
105: step = this .step == null ? 1 : this .step
106: .getIntValue(expressionContext);
107:
108: if (this .var != null)
109: var = this .var.getStringValue(expressionContext);
110:
111: if (this .varStatus != null)
112: varStatus = this .varStatus
113: .getStringValue(expressionContext);
114: } catch (Exception exc) {
115: throw new SAXParseException(exc.getMessage(),
116: getLocation(), exc);
117: } catch (Error err) {
118: throw new SAXParseException(err.getMessage(),
119: getLocation(), new ErrorHolder(err));
120: }
121: ExpressionContext localExpressionContext = new ExpressionContext(
122: expressionContext);
123: int i = 0;
124: // Move to the begin row
125: while (i < begin && iter.hasNext()) {
126: iter.next();
127: i++;
128: }
129: LoopTagStatus status = null;
130: if (varStatus != null) {
131: status = new LoopTagStatus();
132: status.setBegin(begin);
133: status.setEnd(end);
134: status.setStep(step);
135: status.setFirst(true);
136: localExpressionContext.put(varStatus, status);
137: }
138: int skipCounter, count = 1;
139: while (i <= end && iter.hasNext()) {
140: Object value = iter.next();
141: localExpressionContext.setContextBean(value);
142: if (var != null) {
143: localExpressionContext.put(var, value);
144: }
145: if (status != null) {
146: status.setIndex(i);
147: status.setCount(count);
148: status.setFirst(i == begin);
149: status.setCurrent(value);
150: status.setLast((i == end || !iter.hasNext()));
151: }
152: Invoker.execute(consumer, localExpressionContext,
153: executionContext, macroContext, getNext(),
154: getEndInstruction());
155: // Skip rows
156: skipCounter = step;
157: while (--skipCounter > 0 && iter.hasNext()) {
158: iter.next();
159: }
160: // Increase index
161: i += step;
162: count++;
163: }
164: return getEndInstruction().getNext();
165: }
166: }
|