https://saxonica.plan.io/https://saxonica.plan.io/favicon.ico2022-06-15T10:41:39ZSaxonica Developer CommunitySaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=209812022-06-15T10:41:39ZGerrit Imsiekegerrit.imsieke@le-tex.de
<ul></ul><blockquote>
<p>Consider the commented-out code at <a href="https://github.com/gimsieke/xpathle/blob/main/xpathle-lib.xsl#L184" class="external">https://github.com/gimsieke/xpathle/blob/main/xpathle-lib.xsl#L184</a></p>
</blockquote>
<p>It’s now <a href="https://github.com/gimsieke/xpathle/blob/main/xpathle-lib.xsl#L256" class="external">https://github.com/gimsieke/xpathle/blob/main/xpathle-lib.xsl#L256</a></p> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=209842022-06-15T14:06:08ZNorm Tovey-Walsh
<ul><li><strong>Priority</strong> changed from <i>Low</i> to <i>High</i></li><li><strong>Sprint/Milestone</strong> set to <i>SaxonJS 3.0</i></li></ul> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=210872022-06-16T08:48:36ZMartin Honnenmartin.honnen@gmx.de
<ul><li><strong>File</strong> <a href="/attachments/57305">sample2.xml</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/57305/sample2.xml">sample2.xml</a> added</li><li><strong>File</strong> <a href="/attachments/57306">sheet2.xsl</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/57306/sheet2.xsl">sheet2.xsl</a> added</li><li><strong>File</strong> <a href="/attachments/57307">sheet2.xsl.saxoncs-export.sef.json</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/57307/sheet2.xsl.saxoncs-export.sef.json">sheet2.xsl.saxoncs-export.sef.json</a> added</li><li><strong>File</strong> <a href="/attachments/57308">sheet2.xsl.saxonjs-export.sef.json</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/57308/sheet2.xsl.saxonjs-export.sef.json">sheet2.xsl.saxonjs-export.sef.json</a> added</li></ul><p>I have tried to understand what could go wrong, I have not been able to identify what goes wrong, but so far all my attempts suggest that the problem only occurs if SaxonJS runs a SaxonEE exported stylesheet sef.json stylesheet. On the fly or with a SaxonJS/XX compiler generated sef.json stylesheet the problem does not occur.</p>
<p>Sample stylesheet is:</p>
<pre><code class="xml syntaxhl" data-language="xml"><span class="cp"><?xml version="1.0" encoding="utf-8"?></span>
<span class="nt"><xsl:stylesheet</span> <span class="na">xmlns:xsl=</span><span class="s">"http://www.w3.org/1999/XSL/Transform"</span>
<span class="na">version=</span><span class="s">"3.0"</span>
<span class="na">xmlns:xs=</span><span class="s">"http://www.w3.org/2001/XMLSchema"</span>
<span class="na">exclude-result-prefixes=</span><span class="s">"#all"</span>
<span class="na">expand-text=</span><span class="s">"yes"</span><span class="nt">></span>
<span class="nt"><xsl:mode</span> <span class="na">on-no-match=</span><span class="s">"shallow-copy"</span><span class="nt">/></span>
<span class="nt"><xsl:param</span> <span class="na">name=</span><span class="s">"guess-path"</span> <span class="na">select=</span><span class="s">"//@id"</span><span class="nt">/></span>
<span class="nt"><xsl:template</span> <span class="na">match=</span><span class="s">"@*"</span><span class="nt">></span>
<span class="nt"><xsl:next-match/></span>
<span class="nt"><xsl:if</span> <span class="na">test=</span><span class="s">". intersect $guess-path"</span><span class="nt">></span>
<span class="nt"><xsl:attribute</span> <span class="na">name=</span><span class="s">"highlight"</span><span class="nt">></span>test<span class="nt"></xsl:attribute></span>
<span class="nt"></xsl:if></span>
<span class="nt"></xsl:template></span>
<span class="nt"><xsl:template</span> <span class="na">match=</span><span class="s">"/"</span> <span class="na">name=</span><span class="s">"xsl:initial-template"</span><span class="nt">></span>
<span class="nt"><xsl:next-match/></span>
<span class="nt"><xsl:comment></span>Run with {system-property('xsl:product-name')} {system-property('xsl:product-version')} {system-property('Q{http://saxon.sf.net/}platform')}<span class="nt"></xsl:comment></span>
<span class="nt"></xsl:template></span>
<span class="nt"></xsl:stylesheet></span>
</code></pre>
<p>Now when I run it directly or with <code>xslt3</code> (of SaxonJS 2.4) compiled sef.json through <code>xslt3</code> it gives the right output:</p>
<pre><code class="xml syntaxhl" data-language="xml"><span class="cp"><?xml version="1.0" encoding="UTF-8"?></span><span class="nt"><root</span> <span class="na">id=</span><span class="s">"el1"</span> <span class="na">highlight=</span><span class="s">"test"</span> <span class="na">class=</span><span class="s">"foo"</span><span class="nt">></span>
<span class="nt"><item</span> <span class="na">id=</span><span class="s">"el2"</span> <span class="na">highlight=</span><span class="s">"test"</span> <span class="na">class=</span><span class="s">"bar"</span><span class="nt">/></span>
<span class="nt"></root></span><span class="c"><!--Run with SaxonJS 2.4 Node.js--></span>
</code></pre>
<p>However, when I use SaxonCS or EE to compile for SaxonJS, I get the wrong output:</p>
<pre><code class="xml syntaxhl" data-language="xml"><span class="cp"><?xml version="1.0" encoding="UTF-8"?></span><span class="nt"><root</span> <span class="na">id=</span><span class="s">"el1"</span> <span class="na">class=</span><span class="s">"foo"</span><span class="nt">></span>
<span class="nt"><item</span> <span class="na">id=</span><span class="s">"el2"</span> <span class="na">class=</span><span class="s">"bar"</span><span class="nt">/></span>
<span class="nt"></root></span><span class="c"><!--Run with SAXON JS 11.3 Node.js--></span>
</code></pre>
<p>Input sample is e.g.</p>
<pre><code class="xml syntaxhl" data-language="xml"><span class="nt"><root</span> <span class="na">id=</span><span class="s">"el1"</span> <span class="na">class=</span><span class="s">"foo"</span><span class="nt">></span>
<span class="nt"><item</span> <span class="na">id=</span><span class="s">"el2"</span> <span class="na">class=</span><span class="s">"bar"</span><span class="nt">/></span>
<span class="nt"></root></span>
</code></pre>
<p>I am afraid I am not skilled enough to identify whether the SaxonCS/EE generated sef.json is wrong (it doesn't seem to contain an <code>intersect</code>, for instance) or whether the SaxonJS runtime can't handle the perhaps optimized SaxonCS/EE compiled sef.json for that sample.</p> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=210882022-06-16T08:54:50ZGerrit Imsiekegerrit.imsieke@le-tex.de
<ul></ul><p>Thanks Martin for investigating and for preparing a minimal test case!</p> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=210902022-06-16T14:04:02ZMartin Honnenmartin.honnen@gmx.de
<ul></ul><p>SaxonCS/EE seems to compile the <code>intersect</code> check into something like <code>exists(among(..))</code> while SaxonJS seems to compile <code>intersect</code> in the XSLT/XPath into <code>intersect</code> in the SEF as well. But I have now tested that a template matching element nodes instead of attribute nodes and using the same <code>intersect</code> test gives the same SEF compilation with <code>exists(among(..))</code> with SaxonCS/EE but that SaxonJS executes that test fine with element nodes. The SaxonJS <code>among</code> function in the end seems to do <code>===</code> which I think, in terms of JavaScript objects like nodes should do an identity check but from the minimized/garbled source I am not able to see/figure what kind of arguments are processed.</p> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=210912022-06-16T15:01:51ZMartin Honnenmartin.honnen@gmx.de
<ul></ul><p>In terms of <code>among</code> with element nodes it indeed seems that two DOM element nodes end up being compared with <code>===</code>, but as SaxonJS seems to handle attribute nodes differently it appears some wrapper/closure around the node ends up being compared and these wrappers/closures, even if having the same attribute node (data) inside (e.g. <code>id="el1"</code>) compared with <code>===</code> are not the same objects so the comparison returns false. That seems to be basically the reason why the SaxonCS/EE compiled <code>test=". intersect $nodes"</code> fails with <code>.</code> being attribute node and attribute nodes being in <code>$nodes</code>, it does some comparison with <code>among</code> doing some <code>===</code> comparison failing to identify identical attributes as not a DOM attribute node (reference) is compared with another DOM attribute node reference but two SaxonJS data structures that are not the same object but reference the same attribute fail the <code>===</code> comparison.</p> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=210922022-06-16T16:26:43ZMartin Honnenmartin.honnen@gmx.de
<ul></ul><p>Replacing the code in <code>among</code> doing <code>return S===T</code> with <code>return S instanceof Node ? S===T : S.parent === T.parent && S.name === T.name && S.namespaceURI === T.namespaceURI}</code> seems to fix the attribute handling. But I have no idea whether it breaks other things or which other type of wrappers for which the second part after the colon doesn't make sense could be passed to the function.</p> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=210942022-06-17T00:28:07ZMichael Kaymike@saxonica.com
<ul></ul><p>The basic problem is that we are using <code>a === b</code> to compare nodes for identity, and this doesn't work for attributes because the attribute axis constructs attribute nodes "on the fly". We should be using <code>DomUtils.isSameNode(a, b)</code>.</p>
<p>The "among" operator is basically an optimisation for a one-to-many intersect. This is most commonly encountered in a boolean context</p>
<pre><code>if (X intersect (P, Q, R))
</code></pre>
<p>and the main benefit of the optimisation is to avoid sorting nodes into document order. The XJ compiler does this optimisation; XX does not.</p> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=210962022-06-17T14:03:28ZMichael Kaymike@saxonica.com
<ul></ul><p>Come to think of it, the code for "among" has another bug. If we don't sort the sequence into document order, and don't eliminate duplicates, there's a danger that <code>(P intersect (P, Q, R, P))</code> is going to return <code>(P, P)</code>. rather than <code>(P)</code>.</p>
<p>Added a QT3 test case for this: -s:op-intersect -t:K2-SeqIntersect-48</p>
<p>SaxonJ is passing the test because it effectively rewrites the expression as</p>
<pre><code>((P, Q, R, P)[. is P][1])
</code></pre>
<p>That is, it knows the expression can return at most one node so it stops processing the input after one node has been found.</p> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=210972022-06-17T14:19:33ZMichael Kaymike@saxonica.com
<ul></ul><p>I'm inclined to fix this by scrapping the <code>SingletonIntersectExpr</code> ("among" operator) in SaxonJ, rewriting instead as</p>
<pre><code>let $x := §ARG0§ return head(§ARG1§[. is $x])
</code></pre>
<p>and dropping support for "among" in SaxonJS 3 (SEF files will probably need to be recompiled for SaxonJS 3 anyway).</p>
<p>Reducing the number of instructions is always good, as each instruction now carries a lot of code and potential bugs (bytecode, streaming, etc).</p> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=216582022-08-31T14:30:31ZNorm Tovey-Walsh
<ul><li><strong>Sprint/Milestone</strong> changed from <i>SaxonJS 3.0</i> to <i>SaxonJS 2.5</i></li></ul> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=218482022-09-26T09:20:58ZNorm Tovey-Walsh
<ul><li><strong>Sprint/Milestone</strong> changed from <i>SaxonJS 2.5</i> to <i>SaxonJS 3.0</i></li><li><strong>Applies to JS Branch</strong> deleted (<del><i>1.0, 2</i></del>)</li></ul><p>I'm moving this back to Saxon 3. If we're going to rewrite it entirely in 3, requiring SEF files to be recompiled, I don't think there's a lot of value in trying to fix the implementation in 2.x</p> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=218602022-09-27T09:40:52ZNorm Tovey-Walsh
<ul><li><strong>Sprint/Milestone</strong> changed from <i>SaxonJS 3.0</i> to <i>SaxonJS 2.5</i></li></ul><p>On further discussion, perhaps we do want to try to fix this in 2.5.</p> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=218612022-09-27T10:20:07ZMichael Kaymike@saxonica.com
<ul></ul><p>I think the "quick fix" is simply to change the code at Expr.js#89 (in my build) from</p>
<pre><code>node === m
</code></pre>
<p>to</p>
<pre><code>DU.isSameNode(node, m)
</code></pre>
<p>(But check for the potential bug identified in comment #9)</p> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=218632022-09-27T14:34:59ZDebbie Lockettdebbie@saxonica.com
<ul><li><strong>Status</strong> changed from <i>New</i> to <i>Resolved</i></li><li><strong>Applies to JS Branch</strong> <i>2, Trunk</i> added</li><li><strong>Fix Committed on JS Branch</strong> <i>2, Trunk</i> added</li></ul><p>Confirmed that Martin's sample reproduced the issue; unit test iss5560 now added.</p>
<p>Fix in implementation code for "among" in Expr.js (as suggested in comment <a href="#note-10">#note-10</a>) committed on saxonjs2 and main branches.</p>
<p>There doesn't seem to be any problem with potential bug identified in <a href="#note-9">#note-9</a>; the new QT3 test -s:op-intersect -t:K2-SeqIntersect-48 passes with SaxonJS.</p> SaxonJS - Bug #5560: intersect doesn’t seem to work correctly for attributeshttps://saxonica.plan.io/issues/5560?journal_id=219432022-10-04T09:53:34ZNorm Tovey-Walsh
<ul><li><strong>Status</strong> changed from <i>Resolved</i> to <i>Closed</i></li><li><strong>% Done</strong> changed from <i>0</i> to <i>100</i></li><li><strong>Fixed in JS Release</strong> set to <i>SaxonJS 2.5</i></li></ul><p>Fixed in SaxonJS 2.5.</p>