/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.template.instruction; import java.util.Iterator; import java.util.Stack; import org.apache.cocoon.components.expression.ExpressionContext; import org.apache.cocoon.template.environment.ErrorHolder; import org.apache.cocoon.template.environment.ExecutionContext; import org.apache.cocoon.template.environment.ParsingContext; import org.apache.cocoon.template.expression.JXTExpression; import org.apache.cocoon.template.expression.StringTemplateParser; import org.apache.cocoon.template.script.Invoker; import org.apache.cocoon.template.script.event.Event; import org.apache.cocoon.template.script.event.StartElement; import org.apache.cocoon.xml.XMLConsumer; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; /** * @version SVN $Id$ */ public class ForEach extends Instruction { private final JXTExpression items; private final JXTExpression var; private final JXTExpression varStatus; private final JXTExpression begin; private final JXTExpression end; private final JXTExpression step; public ForEach(ParsingContext parsingContext, StartElement raw, Attributes attrs, Stack stack) throws SAXException { super(raw); String name = raw.getLocalName(); Locator locator = getLocation(); String items = attrs.getValue("items"); String select = attrs.getValue("select"); StringTemplateParser expressionCompiler = parsingContext.getStringTemplateParser(); this.var = expressionCompiler.compileExpr(attrs.getValue("var"), null, locator); this.varStatus = expressionCompiler.compileExpr(attrs.getValue("varStatus"), null, locator); this.begin = expressionCompiler.compileInt(attrs.getValue("begin"), name, locator); this.end = expressionCompiler.compileInt(attrs.getValue("end"), name, locator); this.step = expressionCompiler.compileInt(attrs.getValue("step"), name, locator); if (items == null) { if (select == null && (begin == null || end == null)) { throw new SAXParseException("forEach: \"select\", \"items\", or both \"begin\" and \"end\" must be specified", locator, null); } } else if (select != null) { throw new SAXParseException("forEach: only one of \"select\" or \"items\" may be specified", locator, null); } this.items = expressionCompiler.compileExpr(items == null ? select : items, null, locator); } public Event execute(final XMLConsumer consumer, ExpressionContext expressionContext, ExecutionContext executionContext, MacroContext macroContext, Event startEvent, Event endEvent) throws SAXException { Iterator iter = null; int begin, end, step; String var = null, varStatus = null; try { iter = (this.items != null ) ? this.items.getIterator(expressionContext) : JXTExpression.NULL_ITER; begin = this.begin == null ? 0 : this.begin.getIntValue(expressionContext); end = this.end == null ? Integer.MAX_VALUE : this.end.getIntValue(expressionContext); step = this.step == null ? 1 : this.step.getIntValue(expressionContext); if ( this.var != null ) var = this.var.getStringValue(expressionContext); if ( this.varStatus != null ) varStatus = this.varStatus.getStringValue(expressionContext); } catch (Exception exc) { throw new SAXParseException(exc.getMessage(), getLocation(), exc); } catch (Error err) { throw new SAXParseException(err.getMessage(), getLocation(), new ErrorHolder(err)); } ExpressionContext localExpressionContext = new ExpressionContext(expressionContext); int i = 0; // Move to the begin row while (i < begin && iter.hasNext()) { iter.next(); i++; } LoopTagStatus status = null; if (varStatus != null) { status = new LoopTagStatus(); status.setBegin(begin); status.setEnd(end); status.setStep(step); status.setFirst(true); localExpressionContext.put(varStatus, status); } int skipCounter, count = 1; while (i <= end && iter.hasNext()) { Object value = iter.next(); localExpressionContext.setContextBean(value); if (var != null) { localExpressionContext.put(var, value); } if (status != null) { status.setIndex(i); status.setCount(count); status.setFirst(i == begin); status.setCurrent(value); status.setLast((i == end || !iter.hasNext())); } Invoker.execute(consumer, localExpressionContext, executionContext, macroContext, getNext(), getEndInstruction()); // Skip rows skipCounter = step; while (--skipCounter > 0 && iter.hasNext()) { iter.next(); } // Increase index i += step; count++; } return getEndInstruction().getNext(); } }