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
XSLT 3.0: xsl:package and xsl:use-package #762
Comments
This one is quite complicated. First, we must change the xsl:import by a xsl:use-package in the compiled XSpec. This can be done without problem, with some limitations :
For privacy work-around, we may forced to modify tested XSL visibilities, to be able to test them. |
Without So, with the given example, what if XSpec is written like this <x:description stylesheet="package-example.xsl">
<x:scenario>
<x:call function="f:complex-number">
... and it is compiled into like this? <xsl:stylesheet>
<xsl:use-package name="http://example.org/complex-arithmetic.xsl" version="1.0"/>
<xsl:import href=".../src/compiler/generate-tests-utils.xsl"/>
... Will it serve the majority of use cases? Please be warned that I have zero experience with XSLT packages and am just looking at the given example :) |
Thanks for taking the time to look at this. :)
Okay, that makes sense. I've periodically been going through the source code to try and see how it works, but there's a lot in there to follow, and what XSpec does is completely unlike anything I've tried to do in XSLT.
If I'm understanding, this would allow me to test what's in the package itself (which is a good thing!) but I don't see a way that it would allow me to test any contents of the stylesheet that is using the package. With such a simple set of examples, it's hard to come up with a convincing use case, but suppose we had something like:
So then I'd want to create an XSpec test for this (especially since I wrote this out without a reference and it could be full of syntax errors or have other problems) that verifies that something like:
when given as input to the template will yield the correct sum. I'd absolutely be willing to try to add this functionality, but I'm not sure where I'd even begin, especially here - since you need the overrides from xsl:import, it's not obvious to me how to accomplish the same thing without running into the error of importing a stylesheet that uses a package. Maybe as you're transitioning to a 3.0 codebase (I think I saw something about there being plans to make XSpec 2.0 based completely on XSLT 3.0?) there's a solution that uses packages in XSpec's compiler code...somehow? Could the stylesheet under test maybe be recast as some sort of temporary package, allowing you to set visibility or override rules to get the same result as you can with xsl:import? Probably not practical, but all I have are half-formed ideas and speculation at this point. |
What if XSpec takes the following measures when it finds
|
That sounds like a promising approach. |
Again, my knowledge of packaging is extremely limited. There may be a better way. |
I think we could ask Michael Kay for help on this particular point. He previously helped XSpec project with the Coverage java code. |
No, I haven't made any commit. I just tested my previous comment with the given example. What I probably need to know first (except for learning the packages itself...) would be a best practice when you have this working A.xsl <!-- A.xsl -->
<xsl:stylesheet ...>
<!-- Usual xsl:param, xsl:variable, xsl:function, xsl:template etc
including unnamed mode xsl:template -->
</xsl:stylesheet> and working B.xsl <!-- B.xsl -->
<xsl:stylesheet ...>
<xsl:import href="A.xsl" />
<!-- Use stuff in A.xsl, possibly overriding some global xsl:param -->
</xsl:stylesheet> and when <!-- A.xsl revised -->
<xsl:stylesheet ...>
<!-- NEW: Use package -->
<xsl:use-package ... />
<!-- The rest intact -->
</xsl:stylesheet> What is the best practice to rewrite A.xsl and/or B.xsl so that both continue working? Maybe the answer is "it depends"... But I can't go further, as I haven't used the packages myself. My previous comment just came up from Note ("If existing XSLT code has been written to use template rules in the unnamed mode...") in the spec. |
I copy here mail exchanges with Michael Kay, on this topic : Interesting. It's difficult to advise because I don't really know enough about the constraints imposed by the current architecture. I'd be inclined to say: if the stylesheet under test uses packages, then it must itself be (or be treated as) a package, which means XSpec should reference it using xsl:use-package rather than using xsl:import. But I'd also suggest that static linking of the stylesheet under test seems an unnatural thing to do when you've got fn:transform() to achieve dynamic invocation. Under Saxon-JS a lot of our test driver for the XSLT3 test suite is written in XSLT, and it invokes the stylesheet under test using fn:transform(). This seems cleaner because there's no risk of unintended overrides, plus you can test many different stylesheets in a single run with no conflicts of global variables etc. (But I guess XSpec is focussed on testing one stylesheet...) Static variables and parameters are also worth considering here. Although it exposes a bit of a hole in the packaging spec, where it's rather unclear how xsl:use-package is supposed to supply values of static parameters in the used stylesheet. Just to mention another issue that may turn out to be related: static parameters. A particular challenge here is that static coupling of the test driver to the stylesheet under test (whether using xsl:import or xsl:use-package) doesn't allow testing of different values of static parameters in a single run. Dynamic invocation using fn:transform() could solve this problem, as well as the xsl:use-package problem. Mike
|
Thanks, @cmarchand After experimenting I already have an implementation of |
Yes, I agree with you, |
@jcronk @cmarchand , I submitted an experimental implementation: #892 |
I tried testing the code on the pull request, but it's entirely possible that I missed a step or I'm doing something wrong. I initially tried it with several xslt packages, got an error, decided to take a step back and test it with something more minimal, and I got the same error. Here's the minimal example I tried it with: Package: <xsl:package name="com.company.utils.array" package-version="0.1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:array-ext="http://www.company.com/utils/array"
xmlns:array="http://www.w3.org/2005/xpath-functions/array" xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:map="http://www.w3.org/2005/xpath-functions/map" exclude-result-prefixes="#all" expand-text="true" version="3.0">
<xsl:expose component="function" names="array-ext:*" visibility="public"/>
<xsl:function name="array-ext:interlace" as="array(*)*">
<xsl:param name="first-item" as="item()*"/>
<xsl:param name="second-item" as="item()*"/>
<xsl:sequence
select="
for-each-pair($first-item, $second-item, function ($x, $y) {
[$x, $y]
})"
/>
</xsl:function>
<xsl:function name="array-ext:shallow-flatten">
<xsl:param name="ary" as="array(*)"/>
<xsl:sequence select="(1 to array:size($ary)) ! $ary(.)"/>
</xsl:function>
</xsl:package> Stylesheet: <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:array-ext="http://www.company.com/utils/array" exclude-result-prefixes="#all" version="3.0">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:use-package name="com.company.utils.array" package-version="0.1.0"/>
<xsl:variable name="nested-array" select="[1, 2, 3, 4, [5, 6], 7, [8, [9, 10]]]"/>
<xsl:template name="output">
<xsl:variable name="flattened-array" select="array-ext:shallow-flatten($nested-array)"/>
<xsl:sequence select="serialize($flattened-array, map {'method': 'json'})"/>
</xsl:template>
</xsl:stylesheet> and config:
In Oxygen XML, I'm getting: When I run XSpec from the terminal, I get a somewhat more useful stack trace:
The line number in Main-compiled.xsl that it's referencing is an xsl:message containing the scenario label, and the line number in generate-tests-utils.xsl is an xsl:param declaration under the test:report-sequence template. I'm not sure if this is an issue with the code or an issue with something I'm doing. In any case, I don't immediately see where the ClassCastException could be coming from, unless the line numbers it's giving are only approximations. Up until the error hits, it looks like everything is working correctly - it seems to find the package and go through the initial steps just fine. @AirQuick , if you see that I'm making a mistake somewhere, please let me know. |
@jcronk Thanks for testing out the pr. Can you let us know these?
|
Sure, sorry about that. Corrected stylesheet:
Should return something like
From Oxygen, the version of Saxon is 9.8.0.12 (EE), and the version I have XSpec pointing to on the command line is 9.8.0.14 (EE). Here's the xspec file:
I was expecting a failure here, obviously - I usually start with a test I know will fail so I can confirm what XSpec is getting for the result. I thought maybe the string in the I didn't think to run the external_* tests, but I just tried that from the command line and they were all successful; example:
|
This <x:variable name="x:saxon-config" href="SaxonConf.xml"/> or xspec/test/external_xslt-package_filter_use_static-param.xspec Lines 6 to 16 in f922358
I pushed some changes to the pr so that this kind of error is detected: C:\xspec>bin\xspec.bat M:\test\test.xspec
...
Running Tests...
Testing with SAXON EE 9.9.1.7
Scenario for testing function output
ERROR: Invalid $x:saxon-config |
Thanks! I corrected the variable to use href and now both of my basic examples work. So far so good. |
@AirQuick Here's a new one for you: It looks like when I try to test higher-order functions, I get an error. Here's an example of one: Package file: <xsl:package name="hof.reductions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:hof="http://www.company.com/hof"
xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="xs math" version="3.0">
<xsl:function name="hof:reductions" visibility="public">
<xsl:param name="seq"/>
<xsl:param name="init"/>
<xsl:param name="func"/>
<xsl:choose>
<xsl:when test="empty($seq)">
<xsl:sequence select="$seq"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$init, hof:reductions(tail($seq), $func($init, head($seq)), $func)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
</xsl:package> XSpec file: <x:description xmlns:x="http://www.jenitennison.com/xslt/xspec" xmlns:hof="http://www.company.com/hof"
stylesheet="reductions.xsl" run-as="external">
<x:variable name="x:saxon-config" href="../../SaxonConf.xml"/>
<x:scenario label="Scenario for testing function reductions">
<x:call function="hof:reductions">
<x:param name="seq" select="1, 2, 3, 4"/>
<x:param name="init" select="0"/>
<x:param name="func" select="function($res, $inp) { $res + $inp }"/>
</x:call>
<x:expect label="it returns a seq of each step in the reduction" select="0, 1, 3, 6"/>
</x:scenario>
</x:description> When I run this (same setup as before), I get this (the whole stack trace is really long, so this is just the first bit)
There's a comment here in the Saxon documentation that
So this may not even be a bug - what I found after experimenting was that if I run XSpec from the terminal and I set I've run into a couple of other things I wasn't expecting, but I'll need to gather more information to see whether it's worth reporting or if it's just behavior that's happening as a consequence of using packages. Or if it's something about packages that I'm doing wrong, since this is pretty new to me. So I'll update with more if I find anything else that seems noteworthy. Thanks again for putting your branch out there! |
I don't have an official answer from Saxonica, but it seems that if you use
|
Just to update on this, @AirQuick, I've managed to get XSpec to run for a good portion of the codebase I'm converting to packages, and so far everything looks great, at least for my purposes. I ran into an issue with visibility where if I used a function in the XSpec file that was defined in the SUT, it would say it couldn't be found. But maybe I'm not supposed to do that, and in any case, I haven't run across it in a few days (but I'm still rebuilding the stylesheets and tests, since in order to get a fairly sparse example, I had to begin with a lot of what I'd previously had commented out). I'm still working on this, but I want to reiterate my thanks for your answers to my dumb questions. :) There are a number of pieces I have yet to put together, so I'll update if I see any corner cases that look like they may be coming from the XSpec code changes. The worst issue I've seen so far turned out to be an uncaught exception in Saxon itself, where if you use xsl:expose and you put an undeclared namespace prefix in the names attribute, it throws a null pointer exception and gives you no idea where it might be coming from. Just mentioning this in case anyone else tests this branch and is as inattentive as I sometimes can be. |
Right, as listed in the PR description:
If this is going to be a really annoying limitation, we might need to consider introducing something like
I remember I encountered it myself while writing a test for this PR. I didn't have time to report it to Saxonica at that time, but yes, it actually was cryptic. |
Ah, okay. I should have revisited the PR before posting about it.
I was actually going to ask about this separately, since it wasn't directly in the scope of the original issue: something like |
It seemed to me that #127 is too broad, plus it's pretty old, so I wanted to pull this out and call a little more attention to it. There are two points here:
I'm not sure how you get around the conflict between xsl:import and xsl:use-package, though, because I'm sure it's xsl:import and not xsl:include for a reason.
Package: using the example package here
Stylesheet with use-package:
XSpec test:
Here's the saxon config telling it how to find the package:
In Oxygen XML, everything shows up without errors, and the test stylesheet will run and produce output, but if you try to run the XSpec test, you will get:
The text was updated successfully, but these errors were encountered: