Bug #5384
closedUncaught TypeError: Cannot read properties of null (reading 'hashCode')
0%
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
Updated by Oleksii Sapov over 2 years ago
Please, unzip origScoring and modules archives in the same folder.
Updated by Oleksii Sapov over 2 years ago
Hi, is there any feedback on this issue?
Updated by Martin Honnen over 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?
Updated by Martin Honnen over 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
Updated by Michael Kay over 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.
Updated by Martin Honnen over 2 years ago
- File input-sample1.xml input-sample1.xml added
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.
Updated by Michael Kay over 2 years ago
Thanks Martin. I thought that's what I did, but somehow I produced a file that wasn't well-formed.
Updated by Michael Kay over 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.
Updated by Michael Kay over 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