xsl-list
[Top] [All Lists]

Re: [xsl] Saxon & xsltproc giving different output

2011-12-17 18:44:52
There are several "messy" constructs that could be cleaned up. Try cleaning them up and see if this makes the problem go away.

                <xsl:when test='../module_impacted[@arch!=$device_to_output]'>
                <xsl:if test='../module_impacted/text()[.=$current_module]'>
                        <xsl:text></xsl:text>
                </xsl:if>

The predicate [@arch!=$device_to_output] rings alarm bells. When there is no @arch attribute (as in the example input), the predicate should be false. But users writing this often intended to write [not(@arch = $device_to_output)], which is true when @arch is absent. (The ungrammatical comment above the code, however, suggests that the programmer probably intended what was written).

The use of /text() is bad practice. It gives the wrong result when the text includes comments or processing instructions, and it can give the wrong result in some processors using an unnormalized DOM as input (it's not conformant, but some processors allow the input to contain multiple adjacent text nodes). The xsl:if expression should be written test="../module-impacted=$current-module".

That <xsl:text></xsl:text> is pretty strange. XSLT 2.0 is clear that it constructs a zero-length text node, which then disappears when it is added as a child to the document (root) node. XSLT 1.0 is much less clear what happens here. It's far from clear what the author of this code intended. As far as I can see, the xsl:if achieves nothing (the outcome is the same whether the condition is true or false). So there's something fishy here.

There's nothing here where the result is explicitly implementation-defined, but the code is entering some murky waters.

Michael Kay
Saxonica



On 17/12/2011 21:36, Russell Urquhart wrote:
Thanks for your reply Michael.

On Sat, Dec 17, 2011 at 07:05:46PM +0000, Michael Kay wrote:
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.
I suspected that I might have done that. The entire xslt is very large and does 
a lot, and the rest works quite well. I also wasn't trying to get someone to 
debug the whole thing.

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.
Sorry again. Just trying to provide info, to capture the context of the problem 
as i encountered it.

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,

This is what i thought. As i am using Saxon 9, and xsltproc, as i understand 
it, is 1.0 only?



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.
Thinking this was a 1.0 issue, i downloaded Saxon 6.5.5, the last 1.0 processor 
Saxon made, and tried it, but got identical results as i was getting from Saxon 
9.

Let me try and recast my request.

As the variable is defined:

<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>

And the table is generated because:

<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>


How could is_module_in_device have different values for xslt processors?

Thanks,

Russ



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

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail:<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail:<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail:<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--




--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--