Bug #4552

Incorrect output for streamed xsl:message call

Added by Michael Kay 3 months ago. Updated 3 months ago.

Start date:
Due date:
% Done:


Estimated time:
Legacy ID:
Applies to branch:
Fix Committed on Branch:
Fixed in Maintenance Release:


Test case si-message-002 is failing on the 10.1 development branch. The test succeeds in 9.9 and 10.0. It's not clear what has changed.

The first symptom is that 9.9 outputs the warning:

Warning on line 28 column 92 of si-message-A.xsl:
  SXST0067: Execution of xsl:message is not fully streamed

whereas 10.1 is outputting

Warning on line 28 of si-message-A.xsl:
  SXST0067  Execution of consume(consume(((account/transaction[@value lt 0])/@value,
  ...)!.)) is not fully streamed


#1 Updated by Michael Kay 3 months ago

  • Status changed from New to Resolved
  • Priority changed from Low to Normal
  • Applies to branch 10 added
  • Fix Committed on Branch 10 added

The difference in warning messages is spurious: it only occurs because I was running the tests with export:on. But the failure also occurs with export:off.

The relevant change seems to be a change to for bug #4506, which changed the evaluation of xsl:message from pull mode to push mode.

The problem here is that Expression.process() uses the expression's evaluateItem() method if getImplementationMethod() includes Expression.EVALUATE, which class ConsumingOperand does; this is only suitable when the expression returns a singleton, and if used in other cases it truncates the sequence to a single item, which is what we see happening.

There are other expression classes that support Expression.EVALUATE even though they might evaluate to a sequence. But others are more careful: for example CardinalityChecker has the logic:

public int getImplementationMethod() {
        if (!Cardinality.allowsMany(requiredCardinality)) {
            m |= EVALUATE_METHOD;
        return m;

I think the safest thing to do, however, is for Expression.process() to only use the evaluateItem() method after doing a cardinality check on the expression.

#2 Updated by Michael Kay 3 months ago

  • Status changed from Resolved to In Progress

Reopening. The fix caused a regression: test math-1201 (when run with -export:on) fails

java.lang.AssertionError: process() is not implemented in the subclass class net.sf.saxon.expr.NegateExpression

The code for a unary minus expression uses a defaulted method to compute the cardinality of the expression: specifically, it returns the cardinality of the operand expression. So the computed cardinality for -child::price might be zero-or-more. But actually a unary minus expression can only ever return a singleton.

If we evaluate this expression in push mode (e.g because it appears as the body of an element constructor) then we first try the evaluateItem() method, but we're rejecting that because of the incorrect cardinality.

#3 Updated by Michael Kay 3 months ago

  • Status changed from In Progress to Resolved

Two parts to fixing this.

First, NegateExpression (which implements unary minus) should return a static cardinality of (0 or 1).

Secondly, the new fallback code for Expression.process() should be made more robust. There must be either an evaluateItem() method or an iterate() method or both; if both are available then the one we choose should depend on the static cardinality.

Committed these additional changes.

#4 Updated by O'Neil Delpratt 3 months ago

  • % Done changed from 0 to 100
  • Fixed in Maintenance Release 10.1 added

Bug fix committed in the Saxon 10.1 maintenance release.

#5 Updated by O'Neil Delpratt 3 months ago

  • Status changed from Resolved to Closed

Please register to edit this issue

Also available in: Atom PDF