Search in sources :

Example 11 with TemplateSequenceModel

use of freemarker.template.TemplateSequenceModel in project freemarker by apache.

the class ElementModel method get.

/**
 * An Element node supports various hash keys.
 * Any key that corresponds to the tag name of any child elements
 * returns a sequence of those elements. The special key "*" returns
 * all the element's direct children.
 * The "**" key return all the element's descendants in the order they
 * occur in the document.
 * Any key starting with '@' is taken to be the name of an element attribute.
 * The special key "@@" returns a hash of all the element's attributes.
 * The special key "/" returns the root document node associated with this element.
 */
@Override
public TemplateModel get(String key) throws TemplateModelException {
    if (key.equals("*")) {
        NodeListModel ns = new NodeListModel(this);
        TemplateSequenceModel children = getChildNodes();
        int size = children.size();
        for (int i = 0; i < size; i++) {
            NodeModel child = (NodeModel) children.get(i);
            if (child.node.getNodeType() == Node.ELEMENT_NODE) {
                ns.add(child);
            }
        }
        return ns;
    } else if (key.equals("**")) {
        return new NodeListModel(((Element) node).getElementsByTagName("*"), this);
    } else if (key.startsWith("@")) {
        if (key.startsWith("@@")) {
            if (key.equals(AtAtKey.ATTRIBUTES.getKey())) {
                return new NodeListModel(node.getAttributes(), this);
            } else if (key.equals(AtAtKey.START_TAG.getKey())) {
                NodeOutputter nodeOutputter = new NodeOutputter(node);
                return new SimpleScalar(nodeOutputter.getOpeningTag((Element) node));
            } else if (key.equals(AtAtKey.END_TAG.getKey())) {
                NodeOutputter nodeOutputter = new NodeOutputter(node);
                return new SimpleScalar(nodeOutputter.getClosingTag((Element) node));
            } else if (key.equals(AtAtKey.ATTRIBUTES_MARKUP.getKey())) {
                StringBuilder buf = new StringBuilder();
                NodeOutputter nu = new NodeOutputter(node);
                nu.outputContent(node.getAttributes(), buf);
                return new SimpleScalar(buf.toString().trim());
            } else if (key.equals(AtAtKey.PREVIOUS_SIBLING_ELEMENT.getKey())) {
                Node previousSibling = node.getPreviousSibling();
                while (previousSibling != null && !this.isSignificantNode(previousSibling)) {
                    previousSibling = previousSibling.getPreviousSibling();
                }
                return previousSibling != null && previousSibling.getNodeType() == Node.ELEMENT_NODE ? wrap(previousSibling) : new NodeListModel(Collections.emptyList(), null);
            } else if (key.equals(AtAtKey.NEXT_SIBLING_ELEMENT.getKey())) {
                Node nextSibling = node.getNextSibling();
                while (nextSibling != null && !this.isSignificantNode(nextSibling)) {
                    nextSibling = nextSibling.getNextSibling();
                }
                return nextSibling != null && nextSibling.getNodeType() == Node.ELEMENT_NODE ? wrap(nextSibling) : new NodeListModel(Collections.emptyList(), null);
            } else {
                // We don't know anything like this that's element-specific; fall back
                return super.get(key);
            }
        } else {
            // Starts with "@", but not with "@@"
            if (DomStringUtil.isXMLNameLike(key, 1)) {
                Attr att = getAttribute(key.substring(1));
                if (att == null) {
                    return new NodeListModel(this);
                }
                return wrap(att);
            } else if (key.equals("@*")) {
                return new NodeListModel(node.getAttributes(), this);
            } else {
                // We don't know anything like this that's element-specific; fall back
                return super.get(key);
            }
        }
    } else if (DomStringUtil.isXMLNameLike(key)) {
        // We interpret key as an element name
        NodeListModel result = ((NodeListModel) getChildNodes()).filterByName(key);
        return result.size() != 1 ? result : result.get(0);
    } else {
        // We don't anything like this that's element-specific; fall back
        return super.get(key);
    }
}
Also used : TemplateSequenceModel(freemarker.template.TemplateSequenceModel) Element(org.w3c.dom.Element) Node(org.w3c.dom.Node) SimpleScalar(freemarker.template.SimpleScalar) Attr(org.w3c.dom.Attr)

Example 12 with TemplateSequenceModel

use of freemarker.template.TemplateSequenceModel in project freemarker by apache.

the class NodeListModel method get.

public TemplateModel get(String key) throws TemplateModelException {
    int size = size();
    if (size == 1) {
        NodeModel nm = (NodeModel) get(0);
        return nm.get(key);
    }
    if (key.startsWith("@@")) {
        if (key.equals(AtAtKey.MARKUP.getKey()) || key.equals(AtAtKey.NESTED_MARKUP.getKey()) || key.equals(AtAtKey.TEXT.getKey())) {
            StringBuilder result = new StringBuilder();
            for (int i = 0; i < size; i++) {
                NodeModel nm = (NodeModel) get(i);
                TemplateScalarModel textModel = (TemplateScalarModel) nm.get(key);
                result.append(textModel.getAsString());
            }
            return new SimpleScalar(result.toString());
        } else if (key.length() != 2) /* to allow "@@" to fall through */
        {
            // As @@... would cause exception in the XPath engine, we throw a nicer exception now.
            if (AtAtKey.containsKey(key)) {
                throw new TemplateModelException("\"" + key + "\" is only applicable to a single XML node, but it was applied on " + (size != 0 ? size + " XML nodes (multiple matches)." : "an empty list of XML nodes (no matches)."));
            } else {
                throw new TemplateModelException("Unsupported @@ key: " + key);
            }
        }
    }
    if (DomStringUtil.isXMLNameLike(key) || ((key.startsWith("@") && (DomStringUtil.isXMLNameLike(key, 1) || key.equals("@@") || key.equals("@*")))) || key.equals("*") || key.equals("**")) {
        NodeListModel result = new NodeListModel(contextNode);
        for (int i = 0; i < size; i++) {
            NodeModel nm = (NodeModel) get(i);
            if (nm instanceof ElementModel) {
                TemplateSequenceModel tsm = (TemplateSequenceModel) ((ElementModel) nm).get(key);
                if (tsm != null) {
                    int tsmSize = tsm.size();
                    for (int j = 0; j < tsmSize; j++) {
                        result.add(tsm.get(j));
                    }
                }
            }
        }
        if (result.size() == 1) {
            return result.get(0);
        }
        return result;
    }
    XPathSupport xps = getXPathSupport();
    if (xps != null) {
        Object context = (size == 0) ? null : rawNodeList();
        return xps.executeQuery(context, key);
    } else {
        throw new TemplateModelException("Can't try to resolve the XML query key, because no XPath support is available. " + "This is either malformed or an XPath expression: " + key);
    }
}
Also used : TemplateModelException(freemarker.template.TemplateModelException) TemplateNodeModel(freemarker.template.TemplateNodeModel) TemplateSequenceModel(freemarker.template.TemplateSequenceModel) TemplateScalarModel(freemarker.template.TemplateScalarModel) SimpleScalar(freemarker.template.SimpleScalar)

Example 13 with TemplateSequenceModel

use of freemarker.template.TemplateSequenceModel in project PublicCMS-preview by sanluan.

the class TemplateModelUtils method converStringArray.

/**
 * @param model
 * @return string array value
 * @throws TemplateModelException
 */
public static String[] converStringArray(TemplateModel model) throws TemplateModelException {
    if (model instanceof TemplateSequenceModel) {
        TemplateSequenceModel smodel = (TemplateSequenceModel) model;
        String[] values = new String[smodel.size()];
        for (int i = 0; i < smodel.size(); i++) {
            values[i] = converString(smodel.get(i));
        }
        return values;
    }
    String str = converString(model);
    if (CommonUtils.notEmpty(str)) {
        if (0 <= str.indexOf(COMMA_DELIMITED)) {
            return StringUtils.split(str, COMMA_DELIMITED);
        } else {
            return StringUtils.split(str, BLANK_SPACE);
        }
    }
    return null;
}
Also used : TemplateSequenceModel(freemarker.template.TemplateSequenceModel)

Example 14 with TemplateSequenceModel

use of freemarker.template.TemplateSequenceModel in project freemarker by apache.

the class DynamicKeyName method dealWithRangeKey.

private TemplateModel dealWithRangeKey(TemplateModel targetModel, RangeModel range, Environment env) throws UnexpectedTypeException, InvalidReferenceException, TemplateException {
    final TemplateSequenceModel targetSeq;
    final String targetStr;
    if (targetModel instanceof TemplateSequenceModel) {
        targetSeq = (TemplateSequenceModel) targetModel;
        targetStr = null;
    } else {
        targetSeq = null;
        try {
            targetStr = target.evalAndCoerceToPlainText(env);
        } catch (NonStringException e) {
            throw new UnexpectedTypeException(target, target.eval(env), "sequence or " + NonStringException.STRING_COERCABLE_TYPES_DESC, NUMERICAL_KEY_LHO_EXPECTED_TYPES, env);
        }
    }
    final int size = range.size();
    final boolean rightUnbounded = range.isRightUnbounded();
    final boolean rightAdaptive = range.isRightAdaptive();
    // produces an empty sequence, which thus doesn't contain any illegal indexes.
    if (!rightUnbounded && size == 0) {
        return emptyResult(targetSeq != null);
    }
    final int firstIdx = range.getBegining();
    if (firstIdx < 0) {
        throw new _MiscTemplateException(keyExpression, "Negative range start index (", Integer.valueOf(firstIdx), ") isn't allowed for a range used for slicing.");
    }
    final int targetSize = targetStr != null ? targetStr.length() : targetSeq.size();
    final int step = range.getStep();
    // Right-bounded ranges at this point aren't empty, so the right index surely can't reach targetSize.
    if (rightAdaptive && step == 1 ? firstIdx > targetSize : firstIdx >= targetSize) {
        throw new _MiscTemplateException(keyExpression, "Range start index ", Integer.valueOf(firstIdx), " is out of bounds, because the sliced ", (targetStr != null ? "string" : "sequence"), " has only ", Integer.valueOf(targetSize), " ", (targetStr != null ? "character(s)" : "element(s)"), ". ", "(Note that indices are 0-based).");
    }
    final int resultSize;
    if (!rightUnbounded) {
        final int lastIdx = firstIdx + (size - 1) * step;
        if (lastIdx < 0) {
            if (!rightAdaptive) {
                throw new _MiscTemplateException(keyExpression, "Negative range end index (", Integer.valueOf(lastIdx), ") isn't allowed for a range used for slicing.");
            } else {
                resultSize = firstIdx + 1;
            }
        } else if (lastIdx >= targetSize) {
            if (!rightAdaptive) {
                throw new _MiscTemplateException(keyExpression, "Range end index ", Integer.valueOf(lastIdx), " is out of bounds, because the sliced ", (targetStr != null ? "string" : "sequence"), " has only ", Integer.valueOf(targetSize), " ", (targetStr != null ? "character(s)" : "element(s)"), ". (Note that indices are 0-based).");
            } else {
                resultSize = Math.abs(targetSize - firstIdx);
            }
        } else {
            resultSize = size;
        }
    } else {
        resultSize = targetSize - firstIdx;
    }
    if (resultSize == 0) {
        return emptyResult(targetSeq != null);
    }
    if (targetSeq != null) {
        ArrayList /*<TemplateModel>*/
        list = new ArrayList(resultSize);
        int srcIdx = firstIdx;
        for (int i = 0; i < resultSize; i++) {
            list.add(targetSeq.get(srcIdx));
            srcIdx += step;
        }
        // List items are already wrapped, so the wrapper will be null:
        return new SimpleSequence(list, null);
    } else {
        final int exclEndIdx;
        if (step < 0 && resultSize > 1) {
            if (!(range.isAffactedByStringSlicingBug() && resultSize == 2)) {
                throw new _MiscTemplateException(keyExpression, "Decreasing ranges aren't allowed for slicing strings (as it would give reversed text). " + "The index range was: first = ", Integer.valueOf(firstIdx), ", last = ", Integer.valueOf(firstIdx + (resultSize - 1) * step));
            } else {
                // Emulate the legacy bug, where "foo"[n .. n-1] gives "" instead of an error (if n >= 1).
                // Fix this in FTL [2.4]
                exclEndIdx = firstIdx;
            }
        } else {
            exclEndIdx = firstIdx + resultSize;
        }
        return new SimpleScalar(targetStr.substring(firstIdx, exclEndIdx));
    }
}
Also used : TemplateSequenceModel(freemarker.template.TemplateSequenceModel) ArrayList(java.util.ArrayList) SimpleSequence(freemarker.template.SimpleSequence) SimpleScalar(freemarker.template.SimpleScalar)

Example 15 with TemplateSequenceModel

use of freemarker.template.TemplateSequenceModel in project freemarker by apache.

the class DynamicKeyName method dealWithNumericalKey.

private TemplateModel dealWithNumericalKey(TemplateModel targetModel, int index, Environment env) throws TemplateException {
    if (targetModel instanceof TemplateSequenceModel) {
        TemplateSequenceModel tsm = (TemplateSequenceModel) targetModel;
        int size;
        try {
            size = tsm.size();
        } catch (Exception e) {
            size = Integer.MAX_VALUE;
        }
        return index < size ? tsm.get(index) : null;
    }
    try {
        String s = target.evalAndCoerceToPlainText(env);
        try {
            return new SimpleScalar(s.substring(index, index + 1));
        } catch (IndexOutOfBoundsException e) {
            if (index < 0) {
                throw new _MiscTemplateException("Negative index not allowed: ", Integer.valueOf(index));
            }
            if (index >= s.length()) {
                throw new _MiscTemplateException("String index out of range: The index was ", Integer.valueOf(index), " (0-based), but the length of the string is only ", Integer.valueOf(s.length()), ".");
            }
            throw new RuntimeException("Can't explain exception", e);
        }
    } catch (NonStringException e) {
        throw new UnexpectedTypeException(target, targetModel, "sequence or " + NonStringException.STRING_COERCABLE_TYPES_DESC, NUMERICAL_KEY_LHO_EXPECTED_TYPES, (targetModel instanceof TemplateHashModel ? "You had a numberical value inside the []. Currently that's only supported for " + "sequences (lists) and strings. To get a Map item with a non-string key, " + "use myMap?api.get(myKey)." : null), env);
    }
}
Also used : TemplateSequenceModel(freemarker.template.TemplateSequenceModel) TemplateHashModel(freemarker.template.TemplateHashModel) SimpleScalar(freemarker.template.SimpleScalar) TemplateException(freemarker.template.TemplateException)

Aggregations

TemplateSequenceModel (freemarker.template.TemplateSequenceModel)21 TemplateScalarModel (freemarker.template.TemplateScalarModel)9 TemplateModel (freemarker.template.TemplateModel)8 TemplateHashModel (freemarker.template.TemplateHashModel)7 SimpleSequence (freemarker.template.SimpleSequence)6 TemplateNodeModel (freemarker.template.TemplateNodeModel)6 SimpleScalar (freemarker.template.SimpleScalar)5 TemplateNumberModel (freemarker.template.TemplateNumberModel)4 TemplateModelException (freemarker.template.TemplateModelException)3 Test (org.junit.Test)3 TemplateMethodModelEx (freemarker.template.TemplateMethodModelEx)2 TemplateTransformModel (freemarker.template.TemplateTransformModel)2 IOException (java.io.IOException)2 AccessibleObject (java.lang.reflect.AccessibleObject)2 ImmutableList (com.google.common.collect.ImmutableList)1 ImmutableListMultimap (com.google.common.collect.ImmutableListMultimap)1 freemarker.core._TemplateModelException (freemarker.core._TemplateModelException)1 DebugModel (freemarker.debug.DebugModel)1 WrapperTemplateModel (freemarker.ext.util.WrapperTemplateModel)1 AdapterTemplateModel (freemarker.template.AdapterTemplateModel)1