Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(xslt): external transformation #892

Merged
merged 38 commits into from
Jun 22, 2020
Merged

Conversation

AirQuick
Copy link
Member

@AirQuick AirQuick commented Mar 31, 2020

This pull request introduces a new fn:transform()-based test.

Unlike the current xsl:import-based test, this new method is able to test XSLT packages.

Possible use cases

Using this feature

Set /x:description/@run-as = external.

The XSpec schema annotates @run-as as EXPERIMENTAL, because I'm not sure if this entire feature is a viable solution.

Examples

See test/external_*.xspec

Limitations

  • Requires Saxon 9.8.0.8 or later, because of a breaking change in vendor-options of fn:transform().
  • You can't test components in a package unless they are exposed or are made accessible via another component.
  • In .xspec files (x:expect/@select etc.), you can't access variables/functions defined in the tested stylesheet.
  • Not implemented for XQuery.
    • We may possibly use fn:load-xquery-module() from an XSLT-based runner and simplify the XQuery implementation greatly. However,
      • fn:load-xquery-module() requires Saxon-EE.
      • Using an XSLT-based runner will not make sense for non-Saxon XQuery processors.

Global context item where global xsl:param and xsl:variable are evaluated

  • There are limitations inherent in fn:transform().
    • I wonder if there is a finer way to control the global context item.
  • apply-templates invocation (x:context without x:call[@template])
    • If x:context is a single node, the root node of the x:context tree becomes the global context item.
    • If x:context is not a single node, the global context item is absent.
  • call-template invocation (x:call[@template])
    • Each item in x:context becomes not only the context item where the template is called but also the global context item.
  • call-function invocation (x:call[@function])
    • The global context item is absent.
  • We may support Saxon-specific source-location, but I haven't implemented/tested it.

XSpec global parameters and variables

  • XSpec global parameters (/x:description/x:param) take effect in the tested stylesheet. Their corresponding global xsl:param must be declared in the tested stylesheet.
  • XSpec global variables (/x:description/x:variable) are not accessible from the tested stylesheet.

Saxon configuration

  • For your convenience, $x:saxon-config declared by x:variable is passed to fn:transform() as QName('http://saxon.sf.net/', 'configuration') of vendor-options.
    • This may be an abuse of x:variable, but I found it handy for implementing this kind of optional/experimental feature. Thanks @galtm for completing x:variable.
    • On Saxon 9.9.1.6 or less, URI in $x:saxon-config may need to be absolute.
    • When you use $x:saxon-config, the tested stylesheet can't call a function passed as a parameter. (example)
  • I don't know whether SAXON_CUSTOM_OPTIONS (CLI) and saxon.custom.options (Ant) have no effect or partial effect on the tested stylesheet.

Known issues

Tests

test/external_*.xspec.

I have a few more tests in my local repository, but I didn't commit them to this branch for fear of cluttering this pull request prematurely. Once we agree on the outlook of this feature, I'll commit them to this branch.

@AirQuick AirQuick added this to the v2.0.0 milestone Mar 31, 2020
@AirQuick AirQuick requested a review from a team March 31, 2020 10:57
@commit-lint
Copy link

commit-lint bot commented Mar 31, 2020

Features

  • xslt: external transformation (f922358)
  • xslt: util function x:URIQualifiedName() (65e80c3)

Code Refactoring

  • use x:URIQualifiedName() (641c433)
  • util function test:variable-URIQualifiedName() (e15784e)
  • check $x:saxon-config (d0f2c2f)

Contributors

@AirQuick

# Conflicts:
#	src/common/xspec-utils.xsl
#	test/ant/worker/generate.xsl
# Conflicts:
#	src/compiler/generate-xspec-tests.xsl
# Conflicts:
#	src/compiler/generate-xspec-tests.xsl
# Conflicts:
#	src/compiler/generate-common-tests.xsl
@galtm galtm self-requested a review May 9, 2020 15:02
@galtm
Copy link
Member

galtm commented May 9, 2020

@AirQuick , I just wanted you to know I started looking at this pull request. It might take me a while (e.g., 1-2 weeks) to chip away at the review, as I'd like to exercise it a reasonable amount in addition to looking at your code. So far, I'm finding the PR description and tests very helpful.

@AirQuick
Copy link
Member Author

AirQuick commented May 9, 2020

Thanks @galtm. We have plenty of time. Because of its nature, this PR will be kept opened for weeks or even months.

At first, I hoped fn:transform() to be a panacea for #873 and the global variable issue mentioned in #778. Later, the lack of flexibility in global context item disappointed my hope. But this feedback suggests that this experimental feature is still useful for some people.

Copy link
Member

@galtm galtm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feature looks very promising and I think you've done a great job. I think it would be useful to get it out there in the field and let early adopters try it if they don't mind that it is experimental. You wrote that you're not sure if it is a viable solution; are there specific areas you'd like people (either code reviewers or early adopters) to explore and report back on?

Consider adding a test for a public packaged function (or other SUT code) that itself uses transform(). Based on a small experiment, I believe it should work in this XSpec implementation as long as the underlying function works in XSLT, too.

Two documentation-related points:

a) Do you think the Compilation wiki should be enhanced soon to reflect this feature, or do you think its experimental status suggests we should wait? (If we update the wiki, we should probably make the functions public in the compilation-sut.xsl file and maybe others in that folder.)

b) Users shouldn't think that run-as="external" is universally better just because it's newer, and they might find that some of their existing tests cannot use this option. For instance, if the test uses x:call/@function with functions that don't declare any visibility, the test will issue an error like XTDE0041: Cannot invoke function foo#1 externally, because it is not public.

src/compiler/generate-tests-utils.xsl Show resolved Hide resolved
src/compiler/generate-tests-utils.xsl Outdated Show resolved Hide resolved
src/compiler/generate-common-tests.xsl Show resolved Hide resolved
src/compiler/generate-xspec-tests.xsl Show resolved Hide resolved
test/xspec-utils_stylesheet.xspec Outdated Show resolved Hide resolved
@AirQuick
Copy link
Member Author

You wrote that you're not sure if it is a viable solution; are there specific areas you'd like people (either code reviewers or early adopters) to explore and report back on?

The behavior of the global context item seems a bit too unintuitive to me. That's why I wrote "I wonder if there is a finer way to control the global context item." In particular, I'm afraid apply-templates invocation and call-template invocation may be different from what the current XSpec users will expect. (I myself do not use XSpec in conjunction with global context, so I don't know exactly what they will expect.)

@AirQuick
Copy link
Member Author

Consider adding a test for a public packaged function (or other SUT code) that itself uses transform().

A very nice idea. transform() tends to have problems.
I added a test in 179f383 both for @run-as=import (transform.xspec) and =external (external_transform.xspec).

@galtm
Copy link
Member

galtm commented Jun 14, 2020

I added a test in 179f383 both for @run-as=import (transform.xspec) and =external (external_transform.xspec).

The new tests look good. I like that you included the case of XQuery using transform().

@AirQuick
Copy link
Member Author

Two documentation-related points:

a) Do you think the Compilation wiki should be enhanced soon to reflect this feature, or do you think its experimental status suggests we should wait? (If we update the wiki, we should probably make the functions public in the compilation-sut.xsl file and maybe others in that folder.)

b) Users shouldn't think that run-as="external" is universally better just because it's newer, and they might find that some of their existing tests cannot use this option. For instance, if the test uses x:call/@function with functions that don't declare any visibility, the test will issue an error like XTDE0041: Cannot invoke function foo#1 externally, because it is not public.

Opened #1009.

I have a few more tests in my local repository, but I didn't commit them to this branch for fear of cluttering this pull request prematurely. Once we agree on the outlook of this feature, I'll commit them to this branch.

Deferred it to #1010, because there are too many files (50 .xspec files).

@AirQuick AirQuick linked an issue Jun 22, 2020 that may be closed by this pull request
@AirQuick
Copy link
Member Author

Looks like releasing this is better than waiting for more feedback. I'm merging this.
Thanks @galtm for reviewing this and suggesting improvements.

@AirQuick AirQuick merged commit aebf4ba into xspec:master Jun 22, 2020
@AirQuick AirQuick deleted the run-as-external branch June 22, 2020 02:26
This was referenced Jun 22, 2020
@galtm
Copy link
Member

galtm commented Jun 22, 2020

Looks like releasing this is better than waiting for more feedback.

I agree. I haven't had time to delve into your point about the global context item, but at some point I hope to do so, and I can always open a new issue if appropriate. Thanks for developing this feature!

@AirQuick
Copy link
Member Author

Two documentation-related points:
a) Do you think the Compilation wiki should be enhanced soon to reflect this feature, or do you think its experimental status suggests we should wait? (If we update the wiki, we should probably make the functions public in the compilation-sut.xsl file and maybe others in that folder.)
b) Users shouldn't think that run-as="external" is universally better just because it's newer, and they might find that some of their existing tests cannot use this option. For instance, if the test uses x:call/@function with functions that don't declare any visibility, the test will issue an error like XTDE0041: Cannot invoke function foo#1 externally, because it is not public.

Opened #1009.

a) #1237
b) Mentioned it in "Caveats" section of a new Wiki page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

XSLT 3.0: xsl:package and xsl:use-package
2 participants