Re: [xsl] Saxon & xsltproc giving different output

Subject: Re: [xsl] Saxon & xsltproc giving different output
From: Michael Kay <mike@xxxxxxxxxxxx>
Date: Sat, 17 Dec 2011 19:05:46 +0000
There are two ways people can help you with this. Either they can check the code by visual inspection and hope to find the errors that way, or they can run it and debug it. You've provided far too much code for the first approach to be practical, and not enough for the second.

You're also doing your best to confuse the reader by starting with an anecdote about a different problem from the one you are asking for help with.

There are legitimate reasons, incidentally, why two XSLT processors can produce different results on the same input. This is especially true if one of them is an XSLT 2.0 processor and the other is an XSLT 1.0 processor, but it can also happen with two conformant XSLT 1.0 processors, because some aspects of behaviour (such as collating sequences) are explicitly implementation-defined.

Michael Kay
Saxonica



On 17/12/2011 17:05, Russell Urquhart wrote:

Hi,


I have to support a legacy xslt that transforms an xml flle, organizes it, and then outputs a docbook style xml file.

When i took over this, i was running Saxon on the xslt, without incident. Recently i noticted that some elements were not being caught and output. I determined that the previous users had been using xsltproc, so i used that and the output i was getting was in sync with what they had had.

I know that Saxon is the standard, but i didn't have the time or knowledge to discern the differecnes in the xslt.

I am now experiencing a related problem, where stange values are being generated by the xslt, while Saxon does not output any of these specific elements.

The input data, is of the following:

errata_section id="i707" errata_type="caution">
       <title>Adaptive Body Bias Strategy</title>
    <devices_impacted>
         <device_name>xxxx2345</device_name>
         <device_es>1.0</device_es>
         <device_es>1.1</device_es>
	</devices_impacted>
<devices_impacted>
         <device_name>xxxx2346</device_name>
         <device_es>1.0</device_es>
       </devices_impacted>

       <module_impacted>PRCM</module_impacted>
     </errata_section>

The code is called to generate a table of modules impacted, for a given device impacted.

It's called like this:

       <xsl:call-template name="authoring">
           <xsl:with-param name="device_to_output">xxxx2345</xsl:with-param>
       </xsl:call-template>

A key is created:

xsl:key name="module-index" match="errata_section" use="module_impacted"/>


The code in question i think is the following, with original comments in tact (Sorry if there is unnecessary code here):


xsl:template name="table_of_section_per_module">
      <xsl:param name="device_to_output"/>

      <xsl:element name="article">
      <xsl:attribute name="id">errata_module_impacted</xsl:attribute>
      <xsl:attribute name="arch"><xsl:value-of select='$device_to_output'/></xsl:attribute>
      <title>Modules Impacted</title>
<!--     This para element is being deleted here because it causes an error. Para elements cannot contain stuff.-->
<!--<para>-->
      <!-- A little complicated but seems to work fine ! -->
      <xsl:for-each select="//errata_section[generate-id(.)=generate-id(key('module-index', module_impacted)[1])]">
         <xsl:sort select="module_impacted"/>
         <xsl:variable name="current_module"><xsl:value-of select="module_impacted"/></xsl:variable>
         <!-- The is an ugly kludge: we check each section that applies to current chip and update the "is_module_in_device"
             variable if we find it impacts the current module. In the end we have either an empty variable (module is not in
             current device) or a variable containing lots of "o" concatenated (module is in current device) -->

         <xsl:variable name="is_module_in_device">
           <xsl:for-each select="//errata_section/devices_impacted[device_name=$device_to_output]">
	<xsl:choose>
	    	<!-- Start Patch part 1(removing modules having and arch attribute containing a different than the current device) -->
	    	<xsl:when test='../module_impacted[@arch!=$device_to_output]'>
	    	<xsl:if test='../module_impacted/text()[.=$current_module]'>
		   	<xsl:text></xsl:text>
		</xsl:if>
	    	</xsl:when>
		<!-- End Patch part 1 -->
	    	<xsl:otherwise>
		<xsl:if test='../module_impacted/text()[.=$current_module]'><xsl:text>o</xsl:text></xsl:if>
	    	</xsl:otherwise>
	</xsl:choose>
           </xsl:for-each>
         </xsl:variable>
	
	<!-- Start Patch part 2 -->
	<xsl:variable name="removed_modules">
           <xsl:for-each select="//errata_section/devices_impacted[device_name=$device_to_output]">
	<xsl:choose>
	    	<xsl:when test='../module_impacted[@arch!=$device_to_output]'>
	    	<xsl:if test='../module_impacted/text()[.=$current_module]'>
		   	<xsl:text>r</xsl:text>
		</xsl:if>
	    	</xsl:when>
	</xsl:choose>
           </xsl:for-each>
         </xsl:variable>
	<!-- End Patch part 2 -->
	
         <xsl:if test='contains($is_module_in_device, "o")'>
           <xsl:variable name="num_of_sections">
	<!-- Start Patch part 3 -->
             <xsl:value-of select="string-length($is_module_in_device) + string-length($removed_modules)"/>
	<!-- End Patch part 3 -->
           </xsl:variable>

           <table>
            <xsl:attribute name="id">
            <xsl:value-of select="generate-id(module_impacted)"/>
            </xsl:attribute>
             <title>
             <xsl:text>Module</xsl:text>
             <xsl:value-of select="module_impacted"/>
             <xsl:text>  (</xsl:text><xsl:value-of select="$num_of_sections"/><xsl:text>  section</xsl:text>
             <!-- a little grammar ! -->
             <xsl:if test="$num_of_sections&gt;1"><xsl:text>s</xsl:text></xsl:if><xsl:text>)</xsl:text>
             </title>
             <xsl:element name="tgroup">
             <xsl:attribute name="cols">
             <xsl:choose>
               <xsl:when test='$show_review="yes"'>3</xsl:when>
               <xsl:otherwise>2</xsl:otherwise>
             </xsl:choose>
             </xsl:attribute>
             <xsl:element name="colspec">
               <xsl:attribute name="colwidth">1*</xsl:attribute>
               <xsl:attribute name="colname">_1</xsl:attribute>
             </xsl:element>
             <xsl:choose>
                 <xsl:when test='$show_review="yes"'>
                    <xsl:element name="colspec">
                       <xsl:attribute name="colwidth">6*</xsl:attribute>
                       <xsl:attribute name="colname">_2</xsl:attribute>
                    </xsl:element>
                    <xsl:element name="colspec">
                       <xsl:attribute name="colwidth">1*</xsl:attribute>
                       <xsl:attribute name="colname">_3</xsl:attribute>
                    </xsl:element>
                 </xsl:when>
                 <xsl:otherwise>
                    <xsl:element name="colspec">
                       <xsl:attribute name="colwidth">8*</xsl:attribute>
                       <xsl:attribute name="colname">_2</xsl:attribute>
                    </xsl:element>
                 </xsl:otherwise>
             </xsl:choose>
             <tbody>
             <row>
             <xsl:element name="entry">
             <xsl:attribute name="morerows"><xsl:value-of select="$num_of_sections"/></xsl:attribute>
             <xsl:value-of select="module_impacted"/>
             </xsl:element>
             <entry>Section</entry>
             <xsl:if test='$show_review="yes"'>
             <entry>Review status</entry>
             </xsl:if>
             </row>
               <xsl:for-each select="key('module-index', module_impacted)">
                 <xsl:if test="devices_impacted/device_name/text()[.=$device_to_output]">
                   <row>
                   <entry>
		<xsl:value-of select="@id" /><xsl:text>:</xsl:text>
                   <xsl:element name="xref">
                   <xsl:attribute name="linkend">sect_<xsl:value-of select="@id" />
                   </xsl:attribute></xsl:element>
                   </entry>
                   <xsl:if test='$show_review="yes"'>
                   <entry>
                   <xsl:value-of select="review_status" />
                   </entry>
                   </xsl:if>
                    </row>


My issue is, Saxon doesn't find ALL the modules impacted for a given device. Xsltproc, in the past has found all moduls impacted for a given device, but, recently, has incorrectly found unrelated modules impacted, for a given device.


I suspect, by their own admission, that the code at this point is kludgey, and they are taking advantage of some aspect of how xsltproc handles xslt 1.0 style code?

Please any help on this would be great. I want to only have to use Saxon to do this transform!

Thanks again,

Russ

Current Thread