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

net.sf.saxon.trace.XSLTTraceCodeInjector Maven / Gradle / Ivy

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2023 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.trace;

import net.sf.saxon.expr.Expression;
import net.sf.saxon.expr.Literal;
import net.sf.saxon.expr.instruct.*;
import net.sf.saxon.expr.parser.XPathParser;
import net.sf.saxon.functions.TransformFn;
import net.sf.saxon.om.NamespaceUri;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.s9api.Location;
import net.sf.saxon.tree.AttributeLocation;

/**
 * A code injector that wraps every expression (other than a literal) in a TraceExpression, which causes
 * a TraceListener to be notified when the expression is evaluated
 */
public class XSLTTraceCodeInjector extends TraceCodeInjector {

    @Override
    protected boolean isApplicable(Expression exp) {
        if (traceLevel == TraceLevel.HIGH) {
            return !(exp instanceof TraceExpression || exp instanceof OnEmptyExpr || exp instanceof OnNonEmptyExpr);
        }
        return isTraceableExpression(exp);
    }

    /**
     * Decide whether a particular expression should be traced when tracing XSLT stylesheet execution.
     */
    public static boolean isTraceableExpression(Expression exp) {
        // Never trace an empty sequence (it's often an empty sequence constructor, for example 
        if (Literal.isEmptySequence(exp)) {
            return false;
        }
        // Don't trace an on-empty or on-non-empty expression (bug #6428)
        if (exp instanceof OnEmptyExpr || exp instanceof OnNonEmptyExpr) {
            return false;
        }
        // Don't trace an expression if its parent is an XPath expression (as distinct from an XSLT instruction)
        Expression parent = exp.getParentExpression();
        if (parent instanceof TraceExpression) {
            parent = parent.getParentExpression();
        }
        if (exp.isCallOn(TransformFn.class)) {
            return true;
        }
        if (parent != null && parent.getLocation() instanceof XPathParser.NestedLocation) {
            return false;
        }
        // Do trace an expression if it's the direct content of an `xsl:sequence` instruction (which doesn't
        // actually appear on the expression tree in its own right)
        Location loc = exp.getLocation();
        if (loc instanceof XPathParser.NestedLocation) {
            loc = ((XPathParser.NestedLocation) loc).getContainingLocation();
        }
        if (loc instanceof AttributeLocation) {
            StructuredQName elementName = ((AttributeLocation) loc).getElementName();
            return elementName.hasURI(NamespaceUri.XSLT) && elementName.getLocalPart().equals("sequence");
        }
        // Otherwise trace the expression if it has a known location which differs from the parent expression
        // except in the case where the parent expression is a sequence constructor (`Block`)
        return loc != null
                && loc.getLineNumber() != -1
                && !(parent != null && loc == parent.getLocation() && !(parent instanceof Block || parent instanceof ComponentTracer));
    }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy