Project

Profile

Help

Bug #5384

closed

Uncaught TypeError: Cannot read properties of null (reading 'hashCode')

Added by Oleksii Sapov about 2 years ago. Updated about 2 years ago.

Status:
Duplicate
Priority:
Normal
Assignee:
Category:
XSLT Conformance
Sprint/Milestone:
Start date:
2022-03-11
Due date:
% Done:

0%

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

Description

I get this error in Chrome console:

When executing this code:


var options = {
      stylesheetLocation: pathToXsl,
         sourceText: xmlString,    
           stylesheetParams: {"source": "source_A"},
         destination: "document"
}

var result = SaxonJS.transform(options);

I use Saxon-JS 2.3

SEF is generated using xslt3 running on Node.js version v14.17.3.

I can run the XSLT with Saxon 9.8.12-EE in oXygen 20.1 with no problem; same for XSpec. In the attachement are all needed files. In addition, I copied the value of var xmlString to a text file. I tried to comment out the xi:include and xsl:import statements (the SEF in the folder is generated with this state). I can run other SEF in this environment with success, so it is something with XSLT compilation.

Originally posted on StackOverflow: https://stackoverflow.com/questions/71411913/uncaught-typeerror-cannot-read-properties-of-null-reading-hashcode-saxonjs


Files

origScoring.zip (476 KB) origScoring.zip source files Oleksii Sapov, 2022-03-11 09:54
xmlStr.txt (1.14 MB) xmlStr.txt Value of the variable xmlStr Oleksii Sapov, 2022-03-11 09:58
modules.zip (723 Bytes) modules.zip identity-trnasform template Oleksii Sapov, 2022-03-11 11:14
input-sample1.xml (1.12 MB) input-sample1.xml Martin Honnen, 2022-03-23 22:02
Actions #1

Updated by Oleksii Sapov about 2 years ago

Actions #2

Updated by Oleksii Sapov about 2 years ago

Please, unzip origScoring and modules archives in the same folder.

Actions #3

Updated by Oleksii Sapov about 2 years ago

Hi, is there any feedback on this issue?

Actions #4

Updated by Martin Honnen about 2 years ago

Saxon-JS seems to find some circularity in the global maps you have set up, it seems a bug, can you try whether you code works as well if you declare the maps as

 <variable as="map(xs:string, xs:string)" name="map_staves_order" 
    select="map:merge(//choice[@type = 'scoring']/*[@corresp = concat('#', $source)]/scoreDef/descendant::staffDef ! map:entry(string(@n), string(@dme.parts)))"/>


  <variable as="map(xs:string, xs:string)" name="map_new_old_staves"
    select="map:merge(for $key in map:keys($map_staves_order) 
    return map:entry(//measure[@n = 1]/staff[@dme.parts = map:get($map_staves_order, $key)]/@n/string(), $key))"/>

as workaround?

Actions #5

Updated by Martin Honnen about 2 years ago

Norm Tovey-Walsh or Michael Kay, when trying to fix it, a reduced stylesheet that gives the original error is e.g.

<?xml version="1.0" encoding="UTF-8"?>
<stylesheet exclude-result-prefixes="xs xd dme functx dita mei map array" extension-element-prefixes="ixsl" version="3.0" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:array="http://www.w3.org/2005/xpath-functions/array" xmlns:dita="http://dita-ot.sourceforge.net" xmlns:dme="http://www.mozarteum.at/ns/dme" xmlns:functx="http://www.functx.com" xmlns:ixsl="http://saxonica.com/ns/interactiveXSLT" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:mei="http://www.music-encoding.org/ns/mei" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="http://www.music-encoding.org/ns/mei">
    
    <xsl:mode on-no-match="shallow-skip"/>
    
    <!--This parameter is a needed for XSpec. Cf. https://github.com/xspec/xspec/wiki/Global-Context-Item-->
    <param name="global-context-item" select="."/>
    <param name="source" select="'source_A'"/>
    
    <xd:doc>
        <xd:desc>
            <xd:p>Map staffDef@n of the new scoreDef and @dme.parts.</xd:p>
        </xd:desc>
    </xd:doc>
    <variable as="map(xs:string, item())*" name="map_staves_order">
        <for-each select="$global-context-item//choice[@type = 'scoring']/*[@corresp = concat('#', $source)]/scoreDef">
            <map>
                <for-each select="descendant::staffDef">
                    <map-entry key="string(@n)" select="@dme.parts"/>
                </for-each>
            </map>
        </for-each>
    </variable>
    
    <xd:doc>
        <xd:desc>
            <xd:p>Get the maximum number of staves.</xd:p>
        </xd:desc>
    </xd:doc>
    <variable as="xs:integer" name="count_staves" select="
        max(for $a in map:keys($map_staves_order)
        return
        if (matches($a, '\d')) then
        xs:integer($a)
        else
        ())"/>
    
    <xd:doc>
        <xd:desc>
            <xd:p>Key: old @n.</xd:p>
            <xd:p>Value: new @n</xd:p>
        </xd:desc>
    </xd:doc>
    <variable as="map(xs:string, xs:string)*" name="map_new_old_staves">
        <map>
            <for-each select="map:keys($map_staves_order)">
                <variable name="current_key" select="."/>
                <map-entry key="$global-context-item//measure[@n = 1]/staff[@dme.parts = map:get($map_staves_order, $current_key)]/@n/string()" select="."/>
            </for-each>
        </map>
    </variable>
    
    <xsl:template match="/" expand-text="yes">
        <debug xmlns="">{serialize($map_new_old_staves, map { 'method' : 'json', 'indent' : true() })}</debug>
    </xsl:template>
    
    
</stylesheet>

if I add an xsl:message

<?xml version="1.0" encoding="UTF-8"?>
<stylesheet exclude-result-prefixes="xs xd dme functx dita mei map array" extension-element-prefixes="ixsl" version="3.0" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:array="http://www.w3.org/2005/xpath-functions/array" xmlns:dita="http://dita-ot.sourceforge.net" xmlns:dme="http://www.mozarteum.at/ns/dme" xmlns:functx="http://www.functx.com" xmlns:ixsl="http://saxonica.com/ns/interactiveXSLT" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:mei="http://www.music-encoding.org/ns/mei" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="http://www.music-encoding.org/ns/mei">
    
    <xsl:mode on-no-match="shallow-skip"/>
    
    <!--This parameter is a needed for XSpec. Cf. https://github.com/xspec/xspec/wiki/Global-Context-Item-->
    <param name="global-context-item" select="."/>
    <param name="source" select="'source_A'"/>
    
    <xd:doc>
        <xd:desc>
            <xd:p>Map staffDef@n of the new scoreDef and @dme.parts.</xd:p>
        </xd:desc>
    </xd:doc>
    <variable as="map(xs:string, item())*" name="map_staves_order">
        <for-each select="$global-context-item//choice[@type = 'scoring']/*[@corresp = concat('#', $source)]/scoreDef">
            <map>
                <for-each select="descendant::staffDef">
                    <map-entry key="string(@n)" select="@dme.parts"/>
                </for-each>
            </map>
        </for-each>
    </variable>
    
    <xd:doc>
        <xd:desc>
            <xd:p>Get the maximum number of staves.</xd:p>
        </xd:desc>
    </xd:doc>
    <variable as="xs:integer" name="count_staves" select="
        max(for $a in map:keys($map_staves_order)
        return
        if (matches($a, '\d')) then
        xs:integer($a)
        else
        ())"/>
    
    <xd:doc>
        <xd:desc>
            <xd:p>Key: old @n.</xd:p>
            <xd:p>Value: new @n</xd:p>
        </xd:desc>
    </xd:doc>
    <variable as="map(xs:string, xs:string)*" name="map_new_old_staves">
        <map>
            <for-each select="map:keys($map_staves_order)">
                <variable name="current_key" select="."/>
                <map-entry key="$global-context-item//measure[@n = 1]/staff[@dme.parts = map:get($map_staves_order, $current_key)]/@n/string()" select="."/>
            </for-each>
        </map>
    </variable>
    
    <xsl:template match="/" expand-text="yes">
        <xsl:message>map: {serialize($map_new_old_staves, map { 'method' : 'json', 'indent' : true() })}</xsl:message>
        <debug xmlns="">{serialize($map_new_old_staves, map { 'method' : 'json', 'indent' : true() })}</debug>
    </xsl:template>
    
    
</stylesheet>

I get an error about circularity:

xsl:message evaluation at output-map1.xsl#53 failed: TypeError: Cannot read property 'hashCode' of null
Transformation failure: Error XTDE0640 at output-map1.xsl#53
    Circularity in global variable Q{}map_new_old_staves
Error XTDE0640 at output-map1.xsl#53
    Circularity in global variable Q{}map_new_old_staves
Actions #6

Updated by Michael Kay about 2 years ago

Any chance you could supply the input as a well-formed xml file please? I've tried to turn it into a standard XML file but I'm getting reports of non-matching tags. Even better, if the problem can be reproduced with a smaller input file.

Actions #7

Updated by Martin Honnen about 2 years ago

I constructed a file from the input, see attachment.

I used e.g.

const xml = insert-xmlStr.txt-document.here;

fs = require('fs');

fs.writeFile('input-sample1.xml', xml , function (err) {
  if (err) return console.log(err);
});

and then run that with Node.

Actions #8

Updated by Michael Kay about 2 years ago

Thanks Martin. I thought that's what I did, but somehow I produced a file that wasn't well-formed.

Actions #9

Updated by Michael Kay about 2 years ago

I'm not seeing the error on the current build, which seems to confirm that the patch to bug #5230 has addressed the problem (5230 is a long thread and led to discovery of problems unrelated to the original symptoms reported).

The stylesheet doesn't complete successfully, however: it reports

Error XPTY0004 at origScoring.xsl#52
    Required cardinality of first argument of `map:keys()` is exactly one; supplied value is empty

The variable map_staves_order is explicitly declared with type "map(xs:string, item())*" whereas the usage in map:keys() is only going to work if it is a singleton map.

I've discovered that the error goes away if I supply the parameter source=source_A, but I thought I would mention that the stylesheet fails if the parameters are set incorrectly.

Actions #10

Updated by Michael Kay about 2 years ago

  • Status changed from New to Duplicate

Confirmed that both Martin's simplified stylesheets also work without failure on the current development build.

Please register to edit this issue

Also available in: Atom PDF Tracking page