org.jopendocument.dom.template.statements.ForEach Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008 jOpenDocument, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU
* General Public License Version 3 only ("GPL").
* You may not use this file except in compliance with the License.
* You can obtain a copy of the License at http://www.gnu.org/licenses/gpl-3.0.html
* See the License for the specific language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*
*/
package org.jopendocument.dom.template.statements;
import org.jopendocument.dom.template.TemplateException;
import org.jopendocument.dom.template.engine.DataModel;
import org.jopendocument.dom.template.engine.Processor;
import org.jopendocument.util.ExceptionUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.logging.Logger;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.xpath.XPath;
/**
* ForEach tag: repeats a document element for each item in a collection.
* Attributes:
*
* - element (required): the document element to which this tag applies, e.g. "table-row"
* - items (required): expression evaluating to a Collection to be iterated
* - var (required): variable name where the current iteration item is stored
* - alternate (optional): number of document elements to be alternated during iteration,
* typically used for alternating row background colors with a value of "2"
* - multiple (optional): number of document elements to be copied during iteration, not
* compatible with "alternate".
*
*/
public class ForEach extends BaseStatement {
private static Logger logger = Logger.getLogger(ForEach.class.getName());
public ForEach() {
super("forEach");
}
@SuppressWarnings("unchecked")
public void prepare(Element script, Element command) throws TemplateException {
String elementName = command.getAttributeValue("element");
if (elementName == null)
throw new TemplateException("missing required attribute for forEach tag: element");
String itemsExpression = command.getAttributeValue("items");
if (itemsExpression == null)
throw new TemplateException("missing required attribute for forEach tag: items");
String varName = command.getAttributeValue("var");
if (varName == null)
throw new TemplateException("missing required attribute for forEach tag: var");
// alternate
final int alternate;
String alternateString = command.getAttributeValue("alternate");
if (alternateString == null) {
alternate = 1;
} else {
try {
alternate = Integer.parseInt(alternateString);
} catch (Throwable t) {
throw new TemplateException("invalid alternate attribute for forEach tag: " + alternateString);
}
}
// multiple
final int multiple;
final String multipleString = command.getAttributeValue("multiple");
if (multipleString == null) {
multiple = 0;
} else {
try {
multiple = Integer.parseInt(multipleString);
} catch (Throwable t) {
throw new TemplateException("invalid alternate attribute for forEach tag: " + multipleString);
}
}
if (alternate > 1 && multiple > 0) {
throw new TemplateException("both alternate and multiple have been specified");
}
Element element = getAncestorByName(script, elementName);
if (element == null) {
throw new TemplateException("no such element enclosing forEach: " + elementName + " for expression: " + itemsExpression);
}
Element parent = element.getParentElement();
// Element forEachTag = parent.addElement(getQName("forEach")).addAttribute("items",
// itemsExpression).addAttribute("var", varName);
final Element forEachTag = getElement("forEach").setAttribute("items", itemsExpression).setAttribute("var", varName);
final int siblingsToAdd;
if (multiple > 0) {
forEachTag.setAttribute("multiple", "yes");
siblingsToAdd = multiple - 1;
} else {
siblingsToAdd = alternate - 1;
}
int index = parent.indexOf(element);
List targets = new ArrayList();
targets.add(element);
if (siblingsToAdd > 0) {
List siblings;
try {
final XPath xpath = XPath.newInstance("following-sibling::*");
siblings = xpath.selectNodes(element);
} catch (JDOMException e) {
throw ExceptionUtils.createExn(TemplateException.class, "xpath error", e);
}
if (siblingsToAdd > siblings.size())
throw new TemplateException("alternate or multiple is greater (" + (siblingsToAdd + 1) + ") than actual table size (" + siblings.size() + ").");
for (int i = 0; i < siblingsToAdd; i++) {
Element sibling = (Element) siblings.get(i);
targets.add(sibling);
sibling.detach();
}
}
element.detach();
parent.getContent().add(index, forEachTag);
for (int i = 0; i < targets.size(); i++) {
forEachTag.addContent(targets.get(i));
}
script.detach();
}
@SuppressWarnings("unchecked")
public void execute(Processor processor, Element tag, DataModel model) throws TemplateException {
String varName = tag.getAttributeValue("var");
String itemsExpression = tag.getAttributeValue("items");
final boolean multiple = "yes".equals(tag.getAttributeValue("multiple"));
Object value = model.eval(itemsExpression);
if (value == null) {
logger.info("forEach items: null expression: " + itemsExpression);
return;
}
final Collection items;
if (value instanceof Collection)
items = (Collection) value;
else if (value instanceof Object[])
items = Arrays.asList((Object[]) value);
else
items = null;
if (items == null && !(value instanceof Iterator))
throw new TemplateException("forEach items neither a Collection nor an Iterator: " + itemsExpression + " => " + value.getClass() + ":" + value);
List targets = tag.getChildren();
List parentContent = tag.getParentElement().getContent();
int iterationCount = 0;
int index = parentContent.indexOf(tag);
// ne peut utiliser de Map si plusieurs fois le même éléments dans 'items'
final List © 2015 - 2025 Weber Informatics LLC | Privacy Policy