XForms is evaluating most XPath expressions in forms repeatedly. So, it is much more efficient, especially in browsers, to parse them once and preserve some compiled form for repeated evaluations.
Previously, XSLTForms was using XSLT to parse XPath 1.0 expressions
into Javascript code to create objects with a .run()
method. Performance
was good enough but with some unexpected delays for very long node names
in XML instances…
This XPath parser has been rewritten in Javascript to be executed just-in-time when an expression is to be evaluated for the first time. Again, the XSLT stylesheet is lighter and the blank page wait is reduced.
Because the previous parser was targeting XPath 1.0, the new one has been extended to support XQuery 3.1 and generate XQueryX [XQueryX] stored in Javascript arrays (each element or attribute as an array of name and value).
For example,
concat('Hello ', PersonGivenName, '. We hope you like XForms!')
Becomes
[Fleur.XQueryX.functionCallExpr,[ [Fleur.XQueryX.functionName,['concat']], [Fleur.XQueryX.arguments,[ [Fleur.XQueryX.stringConstantExpr,[[Fleur.XQueryX.value,['Hello ']]]], [Fleur.XQueryX.pathExpr,[ [Fleur.XQueryX.stepExpr,[ [Fleur.XQueryX.xpathAxis,['child']], [Fleur.XQueryX.nameTest,['PersonGivenName']] ]] ]], [Fleur.XQueryX.stringConstantExpr,[[Fleur.XQueryX.value,['. We hope you like XForms!']]]] ]] ]]
Which can be serialized in XQueryX as
<xqx:functionCallExpr> <xqx:functionName>concat</xqx:functionName> <xqx:arguments> <xqx:stringConstantExpr> <xqx:value>Hello </xqx:value> </xqx:stringConstantExpr> <xqx:pathExpr> <xqx:stepExpr> <xqx:xpathAxis>child</xqx:xpathAxis> <xqx:nameTest>PersonGivenName</xqx:nameTest> </xqx:stepExpr> </xqx:pathExpr> <xqx:stringConstantExpr> <xqx:value>. We hope you like XForms!</xqx:value> </xqx:stringConstantExpr> </xqx:arguments> </xqx:functionCallExpr>
On Node.js, the XQueryX structure is, then, the input for a new
XQuery engine, named Fleur [Fleur], which also includes a DOM3 engine. It has to
run asynchronous calls on functions such as fn:doc()
, http:send-request()
,
file:write()
, prof:sleep()
,…
Because async
/await
feature was not yet being supported in Node.js and
old browsers, current version Fleur is still struggling with callbacks hell,
call stack overflow. Using this version from XSLTForms would have needed a
massive reorganization of sources: a converter from XQueryX to old XPath
1.0 objects of XSLTForms has, temporarily, been added to remove the
previous XPath 1.0 parser written in XSLT 1.0.
The fleur()
Javascript function has been added to be used within the
Console in the browser debugger to evaluate XPath expressions.
For example,
fleur("instance()")
Returns
"<data xmlns=\"\"><PersonGivenName/></data>"
Because rendering in Javascript console is rather limited, an XForms
console has been created (accessible with F1 key). Currently limited to
expression evaluation, it will be enriched to render, with HTML, Model
Item Properties (type
, relevant
,
required
, valid
,
read-only
,...) bound to
XForms instance data nodes.
With Node.js easily allowing to run an http server, Fleur is also a nice XQuery Web server for XSLTForms to generate inline XML instances, manipulate files, REST APIs,…