Project

Profile

Help

Bug #6302

closed

Saxon (HE; Java) trace not well-formed when XSLT uses transform function

Added by A Galtman 11 months ago. Updated 5 months ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
Diagnostics
Sprint/Milestone:
-
Start date:
2023-12-21
Due date:
% Done:

100%

Estimated time:
Legacy ID:
Applies to branch:
12, trunk
Fix Committed on Branch:
12, trunk
Fixed in Maintenance Release:
Platforms:

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>
Actions #1

Updated by A Galtman 11 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>
Actions #2

Updated by Michael Kay 11 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.

Actions #3

Updated by A Galtman 11 months ago

The issue I'm seeing is about a "trace" start tag without a matching end tag. I just wanted to point that out in case it isn't part of what you're already aware of.

Actions #4

Updated by Michael Kay 11 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).

Actions #5

Updated by A Galtman 11 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.

Actions #6

Updated by Michael Kay 11 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?

Actions #7

Updated by Michael Kay 6 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.

Actions #8

Updated by A Galtman 6 months ago

That sounds like very good news. Thanks!

Actions #9

Updated by Michael Kay 6 months ago

For Saxon 13, the standard trace listener now handles try/catch, so the output remains well-formed when dynamic errors are caught.

Actions #10

Updated by O'Neil Delpratt 5 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

Also available in: Atom PDF