External Transformation - xspec/xspec GitHub Wiki
XSpec v2.0 introduced a new, experimental feature that invokes the tested templates and functions indirectly via fn:transform()
instead of by importing them directly. This feature is controlled by /x:description/@run-as
. This table compares the options for this attribute:
@run-as="import" or Attribute Omitted |
@run-as="external" |
|
---|---|---|
XSpec Imports Tested Stylesheet with xsl:import ? |
Yes | No |
How XSpec Invokes Tested Templates and Functions | Directly | Indirectly, via fn:transform() |
@run-as="external"
is currently an experimental feature and subject to change. Any feedback is welcome.
@run-as="external"
is only for XSLT and Schematron. The @run-as
attribute is ignored in tests for XQuery.
Use Cases
@run-as="external"
will help when you need to
- test an XSLT package
- test different scenarios with different global XSLT parameters (
//x:scenario/x:param
) - test with a static parameter (
/x:description/x:param/@static
or//x:scenario/x:param/@static
) - expect
x:context
to be the global context item - test a stylesheet containing
xsl:result-document
(requires a Saxon bug fix) - specify a Saxon configuration per scenario (
$x:saxon-config
) - test with
@default-mode
How to Use This Feature
Set /x:description/@run-as
= external
.
Examples can be found in test/external_*.xspec
.
Caveats and Limitations
Do not think that @run-as="external"
is universally better just because it's newer. You might find that some of your existing tests cannot use this option.
- You can't test components in a package unless they are exposed or are made accessible via another component.
- Note, in particular, that functions are not exposed by default even if they are in a classic stylesheet (
xsl:stylesheet
orxsl:transform
). If the test usesx:call/@function
with functions that don't declare any visibility, the test will issue an error likeXTDE0041: Cannot invoke function foo#1 externally, because it is not public
. - To test private components, you may want to
- wrap them in an explicit package and expose them using
xsl:expose
, if they are in a classic stylesheet (xsl:stylesheet
orxsl:transform
). - temporarily change their visibility using static parameters, if they are in an explicit package.
- wrap them in an explicit package and expose them using
- Note, in particular, that functions are not exposed by default even if they are in a classic stylesheet (
- In XPath expressions in XSpec files (such as
x:expect/@select
), you can't access variables, functions, keys, or accumulators defined in the tested stylesheet. - You can't override global variables defined in the tested stylesheet.
- Saxon 9.8.0.8 or later is required, because of a breaking change in
vendor-options
offn:transform()
.
Global Context Item
The global context item is a context item where global xsl:param
and xsl:variable
are evaluated.
When @run-as
does not exist or it is @run-as="import"
, the global context item is always absent.
When @run-as="external"
, every XSpec scenario has a different global context item depending on how the tested component is invoked:
x:context
without x:call
)
apply-templates invocation (- If
x:context
is a single node, the root node of thex:context
tree becomes the global context item. - If
x:context
is not a single node, the global context item is absent.
x:call[@template]
) and call-function invocation (x:call[@function]
)
call-template invocation (- If
x:call
is preceded byx:context
, the template (@template
) or the function (@function
) is invoked once for each item inx:context
. Each item inx:context
is the global context item of each invocation. - If
x:call
is not preceded byx:context
, the global context item is absent.
XSpec Global Parameters, Scenario-level Parameters and Global Variables
/x:description/x:param
) and scenario-level parameters (//x:scenario/x:param
)
XSpec global parameters (They take effect in the tested stylesheet, overriding a global xsl:param
element declared there. XSpec tests that use external transformations cannot override global xsl:variable
elements in the tested stylesheet.
/x:description/x:variable
)
XSpec global variables (They do not take effect in the tested stylesheet. They can be used only in XPath expressions in XSpec files (such as x:expect/@select
).
Saxon Configuration
If you need to configure Saxon options for the external transform, you can use x:variable
in your XSpec file to create a variable named $x:saxon-config
. When the test invokes fn:transform
, the input map that defines transformation options includes a vendor-options
map entry whose key is QName('http://saxon.sf.net/', 'configuration')
and whose value is your value of $x:saxon-config
.
Note:
- On Saxon 9.9.1.6 or earlier, URI in
$x:saxon-config
may need to be absolute due to a Saxon bug. - When you use
$x:saxon-config
, the tested stylesheet can't call a function passed as a parameter. (example)
Code Coverage
Code Coverage does not support xsl:use-package
. Stylesheets specified by xsl:use-package
do not appear in the coverage report.
Effect of Default XSLT Mode
The @run-as
attribute determines whether an XSLT stylesheet's @default-mode
attribute takes effect during testing of template rules.
When @run-as
does not exist or it is @run-as="import"
, x:context
elements without a @mode
attribute use the unnamed mode, even if the XSLT stylesheet specifies a default mode.
When @run-as="external"
, x:context
elements without a @mode
attribute use the mode specified in the stylesheet's @default-mode
attribute.