📄 sequencebuiltins.java
字号:
/*
* Copyright (c) 2003 The Visigoth Software Society. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowledgement:
* "This product includes software developed by the
* Visigoth Software Society (http://www.visigoths.org/)."
* Alternately, this acknowledgement may appear in the software itself,
* if and wherever such third-party acknowledgements normally appear.
*
* 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
* project contributors may be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact visigoths@visigoths.org.
*
* 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
* nor may "FreeMarker" or "Visigoth" appear in their names
* without prior written permission of the Visigoth Software Society.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Visigoth Software Society. For more
* information on the Visigoth Software Society, please see
* http://www.visigoths.org/
*/
package freemarker.core;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import freemarker.template.SimpleNumber;
import freemarker.template.TemplateBooleanModel;
import freemarker.template.TemplateDateModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateMethodModelEx;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateModelListSequence;
import freemarker.template.TemplateNumberModel;
import freemarker.template.TemplateScalarModel;
import freemarker.template.TemplateSequenceModel;
import freemarker.template.TemplateCollectionModel;
import freemarker.template.TemplateModelIterator;
import freemarker.template.utility.Constants;
import freemarker.template.utility.StringUtil;
/**
* A holder for builtins that operate exclusively on TemplateSequenceModels.
*/
abstract class SequenceBuiltins {
abstract static class SequenceBuiltIn extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException
{
TemplateModel model = target.getAsTemplateModel(env);
if (!(model instanceof TemplateSequenceModel)) {
throw invalidTypeException(model, target, env, "sequence");
}
return calculateResult((TemplateSequenceModel) model);
}
abstract TemplateModel calculateResult(TemplateSequenceModel tsm)
throws
TemplateModelException;
}
static class firstBI extends SequenceBuiltIn {
TemplateModel calculateResult(TemplateSequenceModel tsm)
throws
TemplateModelException
{
if (tsm.size() == 0) {
return null;
}
return tsm.get(0);
}
}
static class lastBI extends SequenceBuiltIn {
TemplateModel calculateResult(TemplateSequenceModel tsm)
throws
TemplateModelException
{
if (tsm.size() == 0) {
return null;
}
return tsm.get(tsm.size() -1);
}
}
static class reverseBI extends SequenceBuiltIn {
TemplateModel calculateResult(TemplateSequenceModel tsm) {
if (tsm instanceof ReverseSequence) {
return ((ReverseSequence) tsm).seq;
} else {
return new ReverseSequence(tsm);
}
}
private static class ReverseSequence implements TemplateSequenceModel
{
private final TemplateSequenceModel seq;
ReverseSequence(TemplateSequenceModel seq)
{
this.seq = seq;
}
public int size() throws TemplateModelException
{
return seq.size();
}
public TemplateModel get(int index) throws TemplateModelException
{
return seq.get(seq.size() - 1 - index);
}
}
}
static class sortBI extends SequenceBuiltIn {
static final int KEY_TYPE_STRING = 1;
static final int KEY_TYPE_NUMBER = 2;
static final int KEY_TYPE_DATE = 3;
TemplateModel calculateResult(TemplateSequenceModel seq)
throws TemplateModelException {
return sort(seq, null);
}
static String startErrorMessage(Object keys) {
return (keys == null ? "?sort" : "?sort_by(...)") + " failed: ";
}
/**
* Sorts a sequence for the <tt>sort</tt> and <tt>sort_by</tt>
* built-ins.
*
* @param seq the sequence to sort.
* @param keys the name of the subvariable whose value is used for the
* sorting. If the sorting is done by a sub-subvaruable, then this
* will be of length 2, and so on. If the sorting is done by the
* sequene items directly, then this argument has to be 0 length
* array or <code>null</code>.
* @return a new sorted sequence, or the original sequence if the
* sequence length was 0.
*/
static TemplateSequenceModel sort(TemplateSequenceModel seq, String[] keys)
throws TemplateModelException {
int i;
int keyCnt;
int ln = seq.size();
if (ln == 0) {
return seq;
}
List res = new ArrayList(ln);
Object item;
item = seq.get(0);
if (keys != null) {
keyCnt = keys.length;
if (keyCnt == 0) {
keys = null;
} else {
for (i = 0; i < keyCnt; i++) {
if (!(item instanceof TemplateHashModel)) {
throw new TemplateModelException(
startErrorMessage(keys)
+ (i == 0
? "You can't use ?sort_by when the "
+ "sequence items are not hashes."
: "The subvariable "
+ StringUtil.jQuote(keys[i - 1])
+ " is not a hash, so ?sort_by "
+ "can't proceed by getting the "
+ StringUtil.jQuote(keys[i])
+ " subvariable."));
}
item = ((TemplateHashModel) item).get(keys[i]);
if (item == null) {
throw new TemplateModelException(
startErrorMessage(keys)
+ "The " + StringUtil.jQuote(keys[i])
+ " subvariable "
+ (keyCnt == 1
? "was not found."
: "(specified by ?sort_by argument number "
+ (i + 1) + ") was not found."));
}
}
}
} else {
keyCnt = 0;
}
int keyType;
if (item instanceof TemplateScalarModel) {
keyType = KEY_TYPE_STRING;
} else if (item instanceof TemplateNumberModel) {
keyType = KEY_TYPE_NUMBER;
} else if (item instanceof TemplateDateModel) {
keyType = KEY_TYPE_DATE;
} else {
throw new TemplateModelException(
startErrorMessage(keys)
+ "Values used for sorting must be numbers, strings, or date/time values.");
}
if (keys == null) {
if (keyType == KEY_TYPE_STRING) {
for (i = 0; i < ln; i++) {
item = seq.get(i);
try {
res.add(new KVP(
((TemplateScalarModel) item).getAsString(),
item));
} catch (ClassCastException e) {
if (!(item instanceof TemplateScalarModel)) {
throw new TemplateModelException(
startErrorMessage(keys)
+ "All values in the sequence must be "
+ "strings, because the first value "
+ "was a string. "
+ "The value at index " + i
+ " is not string.");
} else {
throw e;
}
}
}
} else if (keyType == KEY_TYPE_NUMBER) {
for (i = 0; i < ln; i++) {
item = seq.get(i);
try {
res.add(new KVP(
((TemplateNumberModel) item).getAsNumber(),
item));
} catch (ClassCastException e) {
if (!(item instanceof TemplateNumberModel)) {
throw new TemplateModelException(
startErrorMessage(keys)
+ "All values in the sequence must be "
+ "numbers, because the first value "
+ "was a number. "
+ "The value at index " + i
+ " is not number.");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -