Project

Profile

Help

Bug #4802

closed

Overzealous optimization

Added by David Priest over 3 years ago. Updated about 3 years ago.

Status:
Closed
Priority:
Low
Assignee:
Category:
-
Sprint/Milestone:
-
Start date:
2020-10-24
Due date:
% Done:

100%

Estimated time:
Applies to JS Branch:
2
Fix Committed on JS Branch:
2
Fixed in JS Release:
SEF Generated with:
Platforms:
Company:
-
Contact person:
-
Additional contact persons:
-

Description

I believe I've discovered a subtle bug, in which an array:for-each fails to process correctly. In the code below there are four console messages labeled A, B, C, D. The console messages are intended to provide detailed insight into the content of the arrays/sub-arrays/maps.

The essense of the program is to read a set of HTML 'span' elements into a document-ordered array of maps; then to re-order the maps into an array of columns, each column as an array of maps; then to swap the row/column value for each map. These changes are reflected in the console output.

The sole difference between the two versions is the use of a saxon:timestamp() to force evaluation of the function.

In the "SwapNoTimestamp" function it appears that array:for-each is passing in the entire array of arrays each time it should be passing in a sub-array. In the "SwapWithTimestamp" function, it correctly passes in the sub-arrays.

Isolating and demonstrating this XPath behaviour was like debugging a black box. Perhaps a future blog post could address techniques for debugging XPath?

Saxon 10.0 plugin for Oxygen 22.1, compiling to Saxon-JS 2.0, executing in Firefox on Ubuntu.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
  expand-text="yes"
  extension-element-prefixes="ixsl saxon"
  version="3.0"
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:array="http://www.w3.org/2005/xpath-functions/array"
  xmlns:f="function"
  xmlns:fn="http://www.w3.org/2005/xpath-functions"
  xmlns:ixsl="http://saxonica.com/ns/interactiveXSLT"
  xmlns:js="http://saxonica.com/ns/globalJS"
  xmlns:map="http://www.w3.org/2005/xpath-functions/map"
  xmlns:saxon="http://saxon.sf.net/"
  xmlns:xhtml="http://www.w3.org/1999/xhtml"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xpath-default-namespace="http://www.w3.org/1999/xhtml">
  <xsl:template
    name="xsl:initial-template">
    <xsl:message>Entering initial-template</xsl:message>
    <xsl:message>A&#9660;</xsl:message>
    <xsl:message>A&#9650; {f:getCells() => f:msg1()}</xsl:message>
    <xsl:message>B&#9660;</xsl:message>
    <xsl:message>B&#9650; { f:getCells() => f:columnOrder() => f:msg2()}</xsl:message>
    <xsl:message>C&#9660;</xsl:message>
    <xsl:message>C&#9650; { f:getCells() => f:columnOrder() => f:swapWithTimestamp() => f:msg2()
      }</xsl:message>
    <xsl:message>D&#9660;</xsl:message>
    <xsl:message>D&#9650; { f:getCells() => f:columnOrder() => f:swapNoTimestamp() => f:msg2() } </xsl:message>
  </xsl:template>
  <xsl:function
    as="array(map(*))"
    name="f:getCells">
    <xsl:sequence
      select="
        array {
          ixsl:page()/id('grid')//span ! map {
            'val': ./text(),
            'row': xs:integer(./count(preceding::span) idiv 3),
            'col': xs:integer(./count(preceding::span) mod 3)
          }
        }" />
  </xsl:function>
  <xsl:function
    as="array(array(map(*)))"
    name="f:columnOrder">
    <xsl:param
      as="array(map(*))"
      name="cells" />
    <xsl:sequence
      select="
        array {
          for $n in 0 to 2
          return
            array:filter($cells, function ($c) {
              xs:integer(map:find($c, 'col')) = xs:integer($n)
            })
        }" />
  </xsl:function>
  <xsl:function
    name="f:swapWithTimestamp">
    <xsl:param
      as="array(array(map(*))*)"
      name="cells" />
    <xsl:message>SwapWithTimestamp {saxon:timestamp()}: {array:size($cells)}</xsl:message>
    <xsl:sequence
      select="
        array:for-each($cells, function ($c) {
          f:swapRowCol($c, array {})
        })" />
  </xsl:function>
  <xsl:function
    name="f:swapNoTimestamp">
    <xsl:param
      as="array(array(map(*))*)"
      name="cells" />
    <xsl:message>SwapNoTimestamp: {array:size($cells)}</xsl:message>
    <xsl:sequence
      select="
        array:for-each($cells, function ($c) {
          f:swapRowCol($c, array {})
        })" />
  </xsl:function>
  <xsl:function
    as="array(map(*))"
    name="f:swapRowCol">
    <xsl:param
      as="array(map(*))"
      name="cells" />
    <xsl:param
      as="array(map(*))"
      name="acc" />
    <xsl:message>Swapping: {array:size($cells)} cells remaining</xsl:message>
    <xsl:sequence
      select="
        if (array:size($cells) gt 0) then
          let $h := array:head($cells)
          return
            f:swapRowCol(array:tail($cells), array:append($acc, map {
              'val': $h('val'),
              'row': $h('col'),
              'col': $h('row')
            }))
        else
          $acc" />
  </xsl:function>
  <xsl:function
    name="f:msg1">
    <xsl:param
      as="array(map(*))"
      name="cells" />
    <xsl:message xml:space="preserve">{array:size($cells)} cells in the array:{array:for-each($cells,function($c){'&#10;val: '||$c('val')||' row: '||$c('row')||' col: '||$c('col')})}</xsl:message>
  </xsl:function>
  <xsl:function
    name="f:msg2">
    <xsl:param
      as="array(array(map(*)*))"
      name="cols" />
    <xsl:message xml:space="preserve">{array:size($cols)} columns in the array:{array:for-each($cols,function($c){'&#10;'||array:size($c)||' cells in column'||f:msg1($c)})}</xsl:message>
  </xsl:function>
</xsl:stylesheet>
<!doctype html>
<html
	lang="en">
	<head>
		<meta
			charset="utf-8">
		<title>Test</title>
		<script src="js/Saxon-JS-2.0/SaxonJS2.rt.js"></script>
		<script type="text/javascript">
      window.onload = function () {
        SaxonJS.transform({
          stylesheetLocation: "xsl/webapp.sef.json",
          initialTemplate: "Q{http://www.w3.org/1999/XSL/Transform}initial-template",
        });
      };</script>
	</head>
	<body>
		<section>
			<h4>Data Source</h4>
			<div
				id="grid">
				<div><span>1</span><span>2</span><span>3</span></div>
				<div><span>4</span><span>5</span><span>6</span></div>
				<div><span>7</span><span>8</span><span>9</span></div>
			</div>
		</section>
	</body>
</html>

Files

webapp.xsl (3.97 KB) webapp.xsl David Priest, 2020-10-24 02:54
index.html (706 Bytes) index.html David Priest, 2020-10-24 02:54

Please register to edit this issue

Also available in: Atom PDF Tracking page