https://saxonica.plan.io/https://saxonica.plan.io/favicon.ico2021-12-21T15:45:16ZSaxonica Developer CommunitySaxonJS - Support #5188: Asynchronous JavaScript Function Call with Map Returnhttps://saxonica.plan.io/issues/5188?journal_id=189112021-12-21T15:45:16ZMichael Kaymike@saxonica.com
<ul></ul><p>There seem to be two separate questions here: one is related to the representation of maps, the other to handling of asynchronous callbacks that return a Promise.</p>
<p>Debbie Lockett can probably provide a better answer than I can on the question of map representations. A Javascript object, as you've observed, can be treated in some ways a bit like a map, but it doesn't have all the functionality of XDM maps, and returning a "real" XDM map would be cleaner.</p>
<p>As regards asynchrony, we're aware that the product needs a major revamp in this area. I don't know if you've seen my Balisage paper sketching out ideas (not yet implemented, sadly) for how to tackle this: see <a href="https://www.balisage.net/Proceedings/vol25/html/Kay01/BalisageVol25-Kay01.html" class="external">https://www.balisage.net/Proceedings/vol25/html/Kay01/BalisageVol25-Kay01.html</a></p>
<p>In the meantime the only real way of tackling asychronous access to external resource such as a Mongo database is to package up the request as one of the things we support in <code>ixsl:schedule-action</code>, typically an HTTP request. I don't know if Mongo already supports an HTTP interface or whether you would need to craft your own, but I would think an HTTP interface where the request and response are both JSON-encoded would be the way to go. This might also answer the question about returning maps, since if you return JSON as a string, the application can then turn it into an XDM map using <code>fn:parse-json()</code>.</p> SaxonJS - Support #5188: Asynchronous JavaScript Function Call with Map Returnhttps://saxonica.plan.io/issues/5188?journal_id=189122021-12-21T19:07:57ZDebbie Lockettdebbie@saxonica.com
<ul></ul><p>Do actually mean that you want to call the MongoDB query <strong>from</strong> the XSLT transform? Or are you actually calling it from JavaScript, and you just want to <strong>pass</strong> the JSON result to XSLT for processing? Your examples suggest that it is the latter; but if it is the former, then I agree with Mike's suggestion to use the HTTP client with <code>ixsl:schedule-action</code>.</p>
<p>Assuming you do indeed intend the former, then to answer your questions about supplying JSON to the transform, and then accessing it as an XDM map in the XSLT stylesheet; there are a number of options available. (It looks like your attempts are overcomplicating things; unless I'm missing something.)</p>
<ol>
<li>You can in fact supply JSON text as the source for the transform. e.g.:</li>
</ol>
<pre><code class="javascript syntaxhl" data-language="javascript"><span class="nx">SaxonJS</span><span class="p">.</span><span class="nx">transform</span><span class="p">({</span><span class="na">sourceText</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">jsonResult</span><span class="p">),</span> <span class="na">sourceType</span><span class="p">:</span> <span class="dl">"</span><span class="s2">json</span><span class="dl">"</span><span class="p">,</span> <span class="p">...})</span>
</code></pre>
<p>then the XDM result (e.g. XDM map or array) of parsing the supplied JSON (following the rules for the <code>fn:json-doc</code> function) becomes the global context item for the transformation. So you could just access it with:</p>
<pre><code class="xml syntaxhl" data-language="xml"><span class="nt"><xsl:variable</span> <span class="na">name=</span><span class="s">"resultMap"</span> <span class="na">select=</span><span class="s">"."</span> <span class="na">as=</span><span class="s">"map(*)"</span><span class="nt">/></span>
</code></pre>
<ol start="2">
<li>Alternatively you could pass that JSON text as a stylesheet parameter:</li>
</ol>
<pre><code class="javascript syntaxhl" data-language="javascript"><span class="nx">SaxonJS</span><span class="p">.</span><span class="nx">transform</span><span class="p">({</span><span class="na">stylesheetParams</span><span class="p">:</span> <span class="p">{</span><span class="na">jsonText</span> <span class="p">:</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">jsonResult</span><span class="p">)},</span> <span class="p">...})</span>
</code></pre>
<p>And as Mike mentioned, use <code>fn:parse-json</code> in your stylesheet to convert the JSON string to an XDM map:</p>
<pre><code class="xml syntaxhl" data-language="xml"><span class="nt"><xsl:parameter</span> <span class="na">name=</span><span class="s">"jsonText"</span> <span class="na">as=</span><span class="s">"xs:string"</span><span class="nt">/></span>
<span class="nt"><xsl:variable</span> <span class="na">name=</span><span class="s">"resultMap"</span> <span class="na">select=</span><span class="s">"parse-json($jsonText)"</span> <span class="na">as=</span><span class="s">"map(*)"</span><span class="nt">/></span>
</code></pre>
<ol start="3">
<li>I'm not quite sure if you can use <code>SaxonJS.getResource()</code> with <code>type:"json"</code>, and <code>SaxonJS.transform({stylesheetParams: {jsonMap :jsonMap}, ...})</code>
with the stylesheet parameter declared as <code><xsl:parameter name="jsonMap" as="map(*)"/></code>. Or if <code>SaxonJS.getResource()</code> with <code>type:"json"</code> just works better with the <code>textResourcePool</code> option for <code>SaxonJS.transform</code> (see <a href="https://www.saxonica.com/saxon-js/documentation/index.html#!api/getResource" class="external">https://www.saxonica.com/saxon-js/documentation/index.html#!api/getResource</a>).</li>
</ol>
<p>One other note: if you're using promises and asynchronous calls, then you probably want an asynchronous
transform too: i.e. SaxonJS.transform({...}, "async") Is that relevant to the issues with getting promises to
work?</p> SaxonJS - Support #5188: Asynchronous JavaScript Function Call with Map Returnhttps://saxonica.plan.io/issues/5188?journal_id=189132021-12-22T09:26:01ZDavid Camps
<ul></ul><p>Michael & Debbie, thanks for the great and fast response to my question. I am a first time SaxonJS user and find the support just as robust and fast as the software…</p>
<p>From the replies I can see using <ixsl:call to get JS promised results is a dead end. Thanks for the insights as to other solutions. One of my design goals was to package the html to be transformed with the db query parameters. Since I can’t do it from within the transform (because of the mongoDB async promises), like you said, do it before and pass the results as <xsl:param. That way I can use the proven SaxonJS.getResource to convert the JSON query result to an XdmMap and deal with the promises before starting the transform.</p>
<p>I will still try to package the query parameters in the html, just imbed something like <dls:query query=”something” /> in the html, pre-parse the html, pull the <dls:query from the DOM, do the queries, deal with promises and pass the html DOM and query results to the transform. I will consider this issue closed.</p> SaxonJS - Support #5188: Asynchronous JavaScript Function Call with Map Returnhttps://saxonica.plan.io/issues/5188?journal_id=202302022-03-28T23:14:55ZMichael Kaymike@saxonica.com
<ul><li><strong>Status</strong> changed from <i>New</i> to <i>Closed</i></li></ul><p>Closing this as the questions have been answered.</p>