So i am new to both fontoxpath and Xquery.
I would like to select a node in a document, then do an insert.
declare %public %updating function xyz:change($bc as document-node(), $ch as element()) {
let $contextNode := evaluateXPath($ch/@contextNode, $bc)
return insert node $ch/element() as last into $contextNode
};
So $ch/@contextNode
is an XPath.
When i change the last bit of the insert line into as last into $bc/changes/*[Last()}
, i do get a result.
The problem is I don't know how to get evaluateXPath to work, so $contextNode
actually point to a node. I keep getting this error when trying several namespaces:
XPST0017: Function evaluateXPath with arity of 2 not registered.
So how can I do this using fontoxpath? Without adding extra dependencies.
Or is this just not yet implemented in fontoxpath?
There is a function evaluateXPath
in the JavaScript API of Fontoxpath, if you wanted to use that from XQuery or XPath you would need to use registerCustomXPathFunction
(the example just shows how to register and use the extension function with normal XPath, I haven't tried with XQuery update):
<script type=module>
// See https://www.npmjs.com/package/fontoxpath documentation.
import * as fontoxpath from 'https://esm.run/fontoxpath';
const namespaceBindings = { 'mf' : 'http://example.com/mf' };
// Register a function called 'evaluateXPath' in the 'http://example.com/mf' namespace:
fontoxpath.registerCustomXPathFunction(
{ namespaceURI: 'http://example.com/mf', localName: 'evaluateXPath' },
['xs:string', 'item()?'],
'item()*',
(_, xpath, contextItem) => fontoxpath.evaluateXPath(xpath, contextItem, null, null, fontoxpath.evaluateXPath.ALL_RESULTS_TYPE, { language: fontoxpath.evaluateXPath.XPATH_3_1_LANGUAGE} )
);
const exampleXML1 = `<root>
<item xpath="/root/data/value"/>
<data>
<value>foo</value>
<value>bar</value>
</data>
</root>`;
const exampleXML1Doc = new DOMParser().parseFromString(exampleXML1, 'application/xml');
console.log(fontoxpath.evaluateXPath('root/item/mf:evaluateXPath(@xpath, .)', exampleXML1Doc, null, null, fontoxpath.evaluateXPath.ALL_RESULTS_TYPE, { namespaceResolver: (prefix) => namespaceBindings[prefix]} ));
</script>
There also seems a predefined function in the namespace http://fontoxml.com/fontoxpath
of the name evaluate
that can be used as follows:
<script type=module>
// See https://www.npmjs.com/package/fontoxpath documentation.
import * as fontoxpath from 'https://esm.run/fontoxpath';
const namespaceBindings = { 'fonto' : 'http://fontoxml.com/fontoxpath' };
const exampleXML1 = `<root>
<item xpath="/root/data/value"/>
<data>
<value>foo</value>
<value>bar</value>
</data>
</root>`;
const exampleXML1Doc = new DOMParser().parseFromString(exampleXML1, 'application/xml');
console.log(fontoxpath.evaluateXPath(`
root/item/fonto:evaluate(string(@xpath), map { '.' : / })`,
exampleXML1Doc, null, null, fontoxpath.evaluateXPath.ALL_RESULTS_TYPE, { namespaceResolver: (prefix) => namespaceBindings[prefix]}));
</script>
To test with XQuery update try e.g.
<script type=module>
// See https://www.npmjs.com/package/fontoxpath documentation.
import * as fontoxpath from 'https://esm.run/fontoxpath';
const namespaceBindings = { 'fonto' : 'http://fontoxml.com/fontoxpath' };
const exampleXML1 = `<root>
<item contextNode="/root/data">
<value>new 1</value>
<value>new 2</value>
</item>
<data>
<value>foo</value>
<value>bar</value>
</data>
</root>`;
const exampleXML1Doc = new DOMParser().parseFromString(exampleXML1, 'application/xml');
const result = fontoxpath.evaluateUpdatingExpressionSync(`
declare %updating function local:change($bc as document-node(), $ch as element()) {
let $contextNode := fonto:evaluate($ch/@contextNode/string(), map { '.' : $bc })
return insert node $ch/element() as last into $contextNode
};
local:change(/, root/item)`,
exampleXML1Doc,
null,
null,
{ namespaceResolver: (prefix) => namespaceBindings[prefix]}
);
fontoxpath.executePendingUpdateList(result.pendingUpdateList);
console.log(exampleXML1Doc.documentElement.outerHTML);
</script>