Project

Profile

Help

Using js:serializeXML() to serialize a variable causes an infinite loop

Added by Eric van der Vlist about 4 years ago

Repro:

<html>
    <head>
        <title>js:serializeXML</title>
        <script type="text/javascript" language="javascript" src="saxon/SaxonceDebug/Saxonce.nocache.js"></script>
        <script type="application/xslt+xml" language="xslt2.0" src="repro-string.xsl" data-initial-template="init"></script>
    </head>
    <body>
        <pre id="document"></pre>
    </body>
</html>

and

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ixsl="http://saxonica.com/ns/interactiveXSLT" 
    xmlns:js="http://saxonica.com/ns/globalJS" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" extension-element-prefixes="ixsl" exclude-result-prefixes="xs xd" 
    version="3.0">

    <xsl:include href="saxon-ce-dummy-declarations.xsl"/>

    <xsl:variable name="document" as="element()">
        <foo/>
    </xsl:variable>

    <xsl:template name="init">
        <xsl:result-document href="#document" method="ixsl:replace-content">
            <xsl:value-of select="js:serializeXML($document)"/>
         </xsl:result-document>
    </xsl:template>

</xsl:stylesheet>

This raises an error (SEVERE: XPathException in invokeTransform: Exception in ixsl:call() (RangeError) : Maximum call stack size exceeded for Chromium, too much recursion for Firefox).

Am I misusing this function or is it a bug?

Thanks,

Eric


Replies (3)

Please register to reply

RE: Using js:serializeXML() to serialize a variable causes an infinite loop - Added by Eric van der Vlist about 4 years ago

Hmmm... just tried with a version built from github and chromium gives me a more explicit message:

SEVERE: XPathException in invokeTransform: Cannot convert class client.net.sf.saxon.ce.tree.linked.ElementImpl to Javascript object 

I guess that this must be the same issue I had when I have tried to save a variable in a JavaScript property: the Saxon implementation of a DOM can't be converted into JavaScript objects.

If that's the case this is a most annoying impedance mismatch between the XSLT world and the browser!

Eric

RE: Using js:serializeXML() to serialize a variable causes an infinite loop - Added by Michael Kay about 4 years ago

The infinite recursion is this bug:

https://saxonica.plan.io/issues/1869

and is fixed when you rebuild from the GitHub source.

js:serializeXML is a wrapper to the serialization code supplied by the DOM implementation, and it doesn't work on a node in Saxon's LinkedTree. I can see a number of possible ways forward here:

(a) implicitly convert a LinkedTree to a DOM as part of the implicit conversion rules for calling JS methods. Most of the code for doing this is already available.

(b) stop using LinkedTree, and use DOM instead for temporary trees. This would be particularly attractive if we can find a way of cutting out the inefficiencies caused by using DOM (which is desirable anyway); the main inefficiency being the handling of namespaces. I'm looking at whether we can preprocess any DOM that we use as input to make sure that every element and attribute node has an explicit namespaceURI property, rather than computing this on demand by searching the tree for in-scope namespace declarations.

(c) provide a serializer capable of serializing any NodeInfo. This could be a lot more compact than the standard serializer if we refrain from providing all the XSLT serialization options, however, it's still extra code. A solution to this might be to provide it in the form of an XSLT module that can be added to the user's stylesheet if required.

RE: Using js:serializeXML() to serialize a variable causes an infinite loop - Added by Eric van der Vlist about 4 years ago

Exactly! About (c), I was actually considering to implement the serialization in XSLT...

A (d) would be to provide a function to explicitly converts LinkedTree to a DOM and which could be useful when you need a DOM for any purposes ( for instance to store an instance as a global object).

It's probably also possible to implement such a function in XSLT by recursively calling DOM method in JavaScript. A low tech alternative if we didn't have this function but had a serialization function working with LinkedTree (c) would be to serialize and parse using JS:ParseXML.

But of course (a) or (b) would make all that stuff (which reminds me of XSLT 1.0 node set / result tree fragment distinction) transparent for XSLT developers and would be my preferred solutions.

Thanks,

Eric

    (1-3/3)

    Please register to reply