Bug #6302
closed![Author: A Galtman](https://www.gravatar.com/avatar/cc758b846fc3ecdad3645517e2348a4c?rating=PG&size=50&default=https%3A%2F%2Fassets.plan.io%2Fimages%2Fdefault_avatar.png)
![Assignee: Michael Kay](https://www.gravatar.com/avatar/db6526d63053f09b62e52c2da8b2230a?rating=PG&size=22&default=https%3A%2F%2Fassets.plan.io%2Fimages%2Fdefault_avatar.png)
Saxon (HE; Java) trace not well-formed when XSLT uses transform function
100%
Description
(I alluded to this in my 12/21/23 comment in https://saxonica.plan.io/issues/6295 but it seems different enough that I'm making a separate issue for it rather than assume that the fix for 6295 is enough.)
The transform()
function seems to cause the Saxon trace not to be well-formed.
Sample XSLT 1, transform-function.xsl¶
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="my-ns"
exclude-result-prefixes="#all"
version="3.0">
<xsl:template name="xsl:initial-template">
<xsl:variable name="transform-options" as="map(xs:string, item()*)">
<xsl:map>
<xsl:map-entry key="'delivery-format'" select="'raw'"/>
<xsl:map-entry key="'stylesheet-location'">target-stylesheet-small.xsl</xsl:map-entry>
<xsl:map-entry key="'function-params'" select="[()]"/>
<xsl:map-entry key="'initial-function'" select="QName('my-ns', 'my:fcn')"/>
</xsl:map>
</xsl:variable>
<xsl:sequence select="transform($transform-options)?output"/>
</xsl:template>
</xsl:stylesheet>
Sample XSLT 2, target-stylesheet-small.xsl¶
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:my="my-ns"
exclude-result-prefixes="#all"
version="3.0">
<xsl:function name="my:fcn" visibility="public" as="xs:string">
<xsl:param name="p" as="empty-sequence()"/>
<xsl:sequence select="'output'"/>
</xsl:function>
</xsl:stylesheet>
Saxon command¶
java -cp "%SAXON_CP%" net.sf.saxon.Transform -opt:0 -T -Tlevel:high -it -xsl:transform-function.xsl 2>transform-function-traceresult.xml
I'm using Saxon-HE 12.4.
Trace Result¶
<trace saxon-version="12.4" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="xsl:initial-template" line="9" column="45" module="transform-function.xsl">
<xsl:variable name="transform-options" line="10" column="73" module="transform-function.xsl">
<trace text="target-stylesheet-small.xsl" line="13" column="52" module="transform-function.xsl">
</trace>
<trace saxon-version="12.4" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:function arity="1" name="my:fcn" line="9" column="66" module="target-stylesheet-small.xsl">
</xsl:function>
</xsl:variable>
</xsl:template>
</trace>
Updated by A Galtman 8 months ago
If I do something similar by making transform() call a template instead of a function, I do not see this problem.
Parent stylesheet that calls transform()¶
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:template name="xsl:initial-template">
<xsl:variable name="transform-options" as="map(xs:string, item()*)">
<xsl:map>
<xsl:map-entry key="'delivery-format'" select="'raw'"/>
<xsl:map-entry key="'stylesheet-location'">target-stylesheet-template.xsl</xsl:map-entry>
<xsl:map-entry key="'source-node'"><x/></xsl:map-entry>
<xsl:map-entry key="'initial-template'" select="QName('', 'template-to-call')"/>
</xsl:map>
</xsl:variable>
<xsl:sequence select="transform($transform-options)?output"/>
</xsl:template>
</xsl:stylesheet>
target-stylesheet-template.xsl containing named template¶
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:template name="template-to-call">
<xsl:sequence select="'output'"/>
</xsl:template>
</xsl:stylesheet>
Well-formed trace result¶
<trace saxon-version="12.4" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="xsl:initial-template" line="8" column="45" module="parent-stylesheet-template.xsl">
<xsl:variable name="transform-options" line="9" column="73" module="parent-stylesheet-template.xsl">
<trace text="target-stylesheet-template.xsl" line="12" column="52" module="parent-stylesheet-template.xsl">
</trace>
<trace name="x" line="13" column="48" module="parent-stylesheet-template.xsl">
</trace>
<trace saxon-version="12.4" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="template-to-call" line="7" column="41" module="target-stylesheet-template.xsl">
</xsl:template>
</trace>
</xsl:variable>
</xsl:template>
</trace>
Updated by Michael Kay 8 months ago
Yes, I'm aware that the trace output is "pseudo-XML". There are cases I know about where namespace prefixes aren't declared. It would probably be a good idea to push the output through a proper serializer, but I've been a bit reluctant because the serializer is likely to do some buffering and it's important not to lose anything if the transformation terminates abruptly.
Updated by Michael Kay 8 months ago
For the missing trace
end tag, I think I would need a repro. There are two possible causes: either the transformation is somehow being run using an API method that fails to write the end tag (and I can't find such a path), or the end tag is being written but not flushed to the output destination.
More generally, I think guaranteeing well-formed output from the trace is going to be a bit of a challenge. The most obvious case where we (apparently) make no attempt currently to achieve this is with try/catch. The other cases that are difficult are where the stylesheet uses multi-threading. Generally the combination of tracing and multi-threading is not going to produce comprehensible output, so the only options are (a) to disallow it, or (b) to produce output that is going to be hard to interpret (and probably ill-formed).
Updated by A Galtman 8 months ago
For the missing trace end tag, I think I would need a repro.
The "Sample XSLT 1, transform-function.xsl", "Sample XSLT 2, target-stylesheet-small.xsl", and "Saxon Command" sections of this issue writeup don't enable you to reproduce the problem with Saxon-HE 12.4? In case platform matters, I am using Windows. If there's other information I should provide, let me know.
Thanks for the observations about try/catch and multi-threading. Though they're not related to my specific reproduction steps here, they're useful to know. Anytime the trace isn't well-formed will be a situation where the code coverage feature in XSpec won't work, and maybe the XSpec documentation should describe limitations on the code coverage feature. So, if you think of any other situations where the trace from Saxon won't be well-formed or won't be accurate, I'd appreciate knowing the information.
Updated by Michael Kay 8 months ago
I'm wondering whether code coverage shouldn't be using a completely different trace listener, which rather than trying to produce a sequential execution trace as output, maintains a histogram of which instructions have been executed how many times? Rather like the TimingTraceListener (-TP option), in fact, but without the timings?
Updated by Michael Kay 4 months ago
- Category set to Diagnostics
- Status changed from New to Resolved
- Assignee set to Michael Kay
- Priority changed from Low to Normal
- Applies to branch 12, trunk added
- Fix Committed on Branch 12, trunk added
Sorry for the delay in responding.
I have made three changes:
(a) a call on fn:transform now has its level raised to that of instructions, which means that by default, fn:transform
calls are included in the trace output.
(b) the header <trace>
line is omitted in a nested transformation, fixing the well-formedness issue.
(c) if function calls are traced (for example fn:transform) the trace now takes the form <call expression="fn:transform">
rather than <fn:transform ...>
, which avoids the need to declare the prefix of the function name.
Updated by Michael Kay 4 months ago
For Saxon 13, the standard trace listener now handles try/catch, so the output remains well-formed when dynamic errors are caught.
Updated by O'Neil Delpratt 2 months ago
- Status changed from Resolved to Closed
- % Done changed from 0 to 100
- Fixed in Maintenance Release 12.5 added
Bug fix applied in the Saxon 12.5 Maintenance release.
Please register to edit this issue