This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 27648 - [xslt 3.0] Dynamic Component References
Summary: [xslt 3.0] Dynamic Component References
Status: CLOSED FIXED
Alias: None
Product: XPath / XQuery / XSLT
Classification: Unclassified
Component: XSLT 3.0 (show other bugs)
Version: Last Call drafts
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Michael Kay
QA Contact: Mailing list for public feedback on specs from XSL and XML Query WGs
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-12-18 00:27 UTC by Michael Kay
Modified: 2015-10-29 09:50 UTC (History)
0 users

See Also:


Attachments

Description Michael Kay 2014-12-18 00:27:38 UTC
In section 3.6.3, Named Components in packages, the paragraph defining "symbolic references" includes some examples; references to accumulator functions should be removed from this list of examples since system functions are not components.

The final paragraph of the section talks of keys being a special case because names are resolved dynamically. This is now also the case for accumulators.
Comment 1 Michael Kay 2014-12-18 08:51:19 UTC
On reflection, I think the problem raised here runs a little deeper than I first thought.

There are three cases, I believe, where we allow dynamic references to component names: these are fn:key, fn:accumulator-before/after, and fn:function-lookup. We don't really have a story on how dynamic component references are resolved in the presence of package-level overrides.

If we wanted to make it precisely analagous to static component references, then we would have to examine the call stack: if template A in package PA calls template B in package PB, B calls C in PC, and C calls function-lookup('F'), then we would look first for function F declared in PC, then for overrides of F in PB, then for overrides of F in PA. This seems complex and onerous (especially for processors that generate code rather than working as interpreters), and it's a little difficult to see how it works if the "calls" are references to global variables rather than function or template calls.

fn:key() is not a problem because keys are private to a package and cannot be overridden.

For fn:function-lookup(), I think it would be quite acceptable to say that it searches only within the package containing the call on function-lookup, disregarding any overrides.

That leaves accumulators. I can see three ways forward:

(a) define the dynamic binding algorithm to take account of the call stack as proposed above, with all its potential difficulties.

(b) revert to a syntax for invoking accumulators where the accumulator name is bound statically. Perhaps (b1) by making an accumulator declare a function, as we did before, or (b2) by replacing the functions accumulator-before and accumulator-after with instructions along the lines of call-template.

(c) change accumulators to be like keys: always private to a package, with no override allowed. If you want to expose accumulator values to other packages, define a function that wraps the call on accumulator-before/after; if you want to override an accumulator, override the wrapping function with a call to a different accumulator.

We should also take into account the "applies-to" mechanism, or its replacement, wich establishes an association between accumulators and source documents. If we tell the system to evaluate accumulator A against document D, which A do we mean, in the case where there are overrides?

Taking all these factors into account, and given where we are in the development cycle, my preference is for (c) as the least disruptive change. This means: no change to the syntax other than removing xsl:accumulator as a permitted child of xsl:override; no need to define complex new semantics for dynamic component binding; it's not a serious restriction of capability; and there's already a good precedent in the way we do keys.
Comment 2 Michael Kay 2014-12-18 10:01:48 UTC
Commenting on my own proposal, the difficulty with wrapping accumulator calls in functions is making the functions streamable; we can't replicate the static analysis we do on accumulator-after() if the call is hidden within a user-defined function.

So I would like to explore b(2): replacing the functions accumulator-before() and accumulator-after() with a pair of instructions <xsl:accumulator-before name="a"/> and <xsl:accumulator-after name="a"/> (or a single instruction with an extra attribute if people prefer).

Of course, there's a usability disadvantage, we all know how awkward it is to call xsl:number in any context except where you want to output the value directly into the result tree. But people know how to live with that.

The advantages would be (a) the normal static binding rules can be used to handle overrides, (b) there's more scope for optimization and static error checking if the accumulator is identified statically (e.g. the type of the result is always statically known), (c) it slightly simplifies the streamability rules, e.g. rules 6 and 7 of 19.8.8.1 disappear.
Comment 3 Michael Kay 2015-01-15 22:02:03 UTC
At the WG telcon today, the WG found itself leaning towards option 1(c), and the editor was asked to draft a formal proposal. Here it is.

In 3.6.3, Named Components in Packages:

Delete accumulators from the list here:

The components which can be declared in one package and referenced in another are: functions, named templates, attribute sets, modes, accumulators, and global variables and parameters.

Add accumulators here ("keys and accumulators"):

In addition, keys are classified as named components ...

In "Examples of constructs that give rise to symbolic references..., ; and XPath function calls referring to stylesheet functions or accumulator functions.], delete "or accumulator functions".

In "Keys behave rather differently from other components. " generalize the text so it covers accumulators as well as keys.

But observe that accumulators can also be referenced statically, in the use-accumulators attribute of xsl:global-context-item and xsl:stream and xsl:merge-source. These references are like other references to private components: the declaration must be in the same package as the reference.

In 3.6.3.1 visibility of components

Delete accumulators from the list of components that have a visibility attribute.

Delete xsl:accumulator from the content model of xsl:expose.

In 3.6.3.2 accepting components

Delete xsl:accumulator from the content model of xsl:accept.

In 3.6.3.3 Overriding Components from a Used Package

Delete xsl:accumulator from the content model of xsl:override.

Remove text referring specifically to overriding of accumulators, including the rules for compatibility of accumulators.

Add a section

3.6.3.5 Dynamic references to components

(Precis)

There are several functions in which a dynamically-evaluated QName is used to identify a component: key(), accumulator-before/after(), function-lookup().

In all these cases, the set of components that are available to be referenced are those that are declared in the package where this function call appears. The reference succeeds irrespective of the visibility of the component, unless the visibility is abstract (applies to functions only) in which case it is not available to be referenced in this way. If (this also applies only to functions) the relevant component has been overridden, the overriding declarations are not considered. However, a function declared within xsl:override will be found, provided the function-lookup call appears in the same package as the xsl:override.

[Check and reiterate the rules for dynamic invocations of key(), accumulator-before/after(), and function-lookup()].

In 3.6.5 Declarations Local to a Package

"Declarations of keys, decimal formats, namespace aliases..." - add accumulators. 

In 18.2.1 Delete the visibility attribute of xsl:accumulator

In 18.2.5, error condition [ERR XTDE3340], change "accumulator visible in the package" to "accumulator declared in the package".

Delete section 18.2.7, but retain [ERR XTSE3350], moving it into 18.2.1.
Comment 4 Michael Kay 2015-01-30 23:03:02 UTC
The changes were accepted and have been applied.