All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.expr.instruct.Choose Maven / Gradle / Ivy

There is a newer version: 10.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2013 Saxonica Limited.
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.expr.instruct;





import net.sf.saxon.Configuration;
import net.sf.saxon.TypeCheckerEnvironment;
import net.sf.saxon.evpull.EmptyEventIterator;
import net.sf.saxon.evpull.EventIterator;
import net.sf.saxon.expr.*;
import net.sf.saxon.expr.parser.*;
import net.sf.saxon.functions.BooleanFn;
import net.sf.saxon.functions.SystemFunctionCall;
import net.sf.saxon.om.Item;
import net.sf.saxon.om.SequenceIterator;
import net.sf.saxon.om.StandardNames;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.pattern.ConditionalPattern;
import net.sf.saxon.pattern.Pattern;
import net.sf.saxon.trace.ExpressionPresenter;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.tree.iter.EmptyIterator;
import net.sf.saxon.tree.util.FastStringBuffer;
import net.sf.saxon.type.*;
import net.sf.saxon.value.BooleanValue;
import net.sf.saxon.value.Cardinality;
import net.sf.saxon.value.SequenceType;

import java.util.Iterator;
import java.util.List;


/**
 * Compiled representation of an xsl:choose or xsl:if element in the stylesheet.
 * Also used for typeswitch in XQuery.
*/

public class Choose extends Instruction {

    // The class implements both xsl:choose and xsl:if. There is a list of boolean
    // expressions (conditions) and a list of corresponding actions: the conditions
    // are evaluated in turn, and when one is found that is true, the corresponding
    // action is evaluated. For xsl:if, there is always one condition and one action.
    // An xsl:otherwise is compiled as if it were xsl:when test="true()". If no
    // condition is satisfied, the instruction returns an empty sequence.

    private Expression[] conditions;
    private Expression[] actions;


    /**
    * Construct an xsl:choose instruction
    * @param conditions the conditions to be tested, in order
    * @param actions the actions to be taken when the corresponding condition is true
    */

    public Choose(Expression[] conditions, Expression[] actions) {
        this.conditions = conditions;
        this.actions = actions;
        if (conditions.length != actions.length) {
            throw new IllegalArgumentException("Choose: unequal length arguments");
        }
        for (int i=0; i or "when (test) then ()"

        if (/*Literal.isConstantBoolean(conditions[conditions.length-1], true) && */
                Literal.isEmptySequence(actions[actions.length-1])) {
            if (conditions.length == 1) {
                return Literal.makeEmptySequence();
            } else {
                Expression[] c = new Expression[conditions.length-1];
                System.arraycopy(conditions, 0, c, 0, conditions.length-1);
                Expression[] a = new Expression[actions.length-1];
                System.arraycopy(actions, 0, a, 0, actions.length-1);
                conditions = c;
                actions = a;
            }
        }

        // Flatten an "else if"

        if (Literal.isConstantBoolean(conditions[conditions.length-1], true) &&
                actions[actions.length-1] instanceof Choose) {
            Choose choose2 = (Choose)actions[actions.length-1];
            int newLen = conditions.length + choose2.conditions.length - 1;
            Expression[] c2 = new Expression[newLen];
            Expression[] a2 = new Expression[newLen];
            System.arraycopy(conditions, 0, c2, 0, conditions.length - 1);
            System.arraycopy(actions, 0, a2, 0, actions.length - 1);
            System.arraycopy(choose2.conditions, 0, c2, conditions.length - 1, choose2.conditions.length);
            System.arraycopy(choose2.actions, 0, a2, actions.length - 1, choose2.actions.length);
            conditions = c2;
            actions = a2;
        }

        // Rewrite "if (EXP) then true() else false()" as boolean(EXP)

        if (conditions.length == 2 &&
                Literal.isConstantBoolean(actions[0], true) &&
                Literal.isConstantBoolean(actions[1], false) &&
                Literal.isConstantBoolean(conditions[1], true)) {
            TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy();
            if (th.isSubType(conditions[0].getItemType(th), BuiltInAtomicType.BOOLEAN) &&
                        conditions[0].getCardinality() == StaticProperty.EXACTLY_ONE) {
                return conditions[0];
            } else {
                return SystemFunctionCall.makeSystemFunction("boolean", new Expression[]{conditions[0]});
            }
        }
        return this;
    }

    /*@NotNull*/
    public Expression typeCheck(ExpressionVisitor visitor, ExpressionVisitor.ContextItemType contextItemType) throws XPathException {
        for (int i=0; i iterateSubExpressions() {
        return new Iterator() {
            boolean doingConditions = true;
            int index = 0;
            public boolean hasNext() {
                return doingConditions || index iterateSubExpressionInfo() {
         return new Iterator() {
             boolean doingConditions = true;
             int index = 0;
             public boolean hasNext() {
                 return doingConditions || index
     * 

The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

* * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the set of PathMap nodes to which the paths from this expression should be appended * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { // expressions used in a condition contribute paths, but these do not contribute to the result for (Expression condition : conditions) { condition.addToPathMap(pathMap, pathMapNodeSet); } PathMap.PathMapNodeSet result = new PathMap.PathMapNodeSet(); for (Expression action : actions) { PathMap.PathMapNodeSet temp = action.addToPathMap(pathMap, pathMapNodeSet); result.addNodeSet(temp); } return result; } /** * The toString() method for an expression attempts to give a representation of the expression * in an XPath-like form, but there is no guarantee that the syntax will actually be true XPath. * In the case of XSLT instructions, the toString() method gives an abstracted view of the syntax * @return a representation of the expression as a string */ public String toString() { FastStringBuffer sb = new FastStringBuffer(FastStringBuffer.SMALL); sb.append("if ("); for (int i=0; i iterate(XPathContext context) throws XPathException { for (int i=0; i *

The events (of class {@link net.sf.saxon.evpull.PullEvent}) are either complete * items, or one of startElement, endElement, startDocument, or endDocument, known * as semi-nodes. The stream of events may also include a nested EventIterator. * If a start-end pair exists in the sequence, then the events between * this pair represent the content of the document or element. The content sequence will * have been processed to the extent that any attribute and namespace nodes in the * content sequence will have been merged into the startElement event. Namespace fixup * will have been performed: that is, unique prefixes will have been allocated to element * and attribute nodes, and all namespaces will be declared by means of a namespace node * in the startElement event or in an outer startElement forming part of the sequence. * However, duplicate namespaces may appear in the sequence.

*

The content of an element or document may include adjacent or zero-length text nodes, * atomic values, and nodes represented as nodes rather than broken down into events.

* * @param context The dynamic evaluation context * @return the result of the expression as an iterator over a sequence of PullEvent objects * @throws net.sf.saxon.trans.XPathException * if a dynamic error occurs during expression evaluation */ public EventIterator iterateEvents(XPathContext context) throws XPathException { for (int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy