How to call a custom xquery function in exist-db using the REST API ?
Is it possible to have more than 1 function in the xquery file ?
declare function local:toto() as node() {
return doc("/db/ProjetXML/alice.xml")/raweb/identification/projectName)
};
declare function local:pomme() as node() {
return doc("/db/ProjetXML/carmen.xml")/raweb/identification/projectSize);
};
If I call it using :
http://localhost:8080/exist/rest/db/ProjetXML/orange.xqy?_query=local:toto()
I get the following error :
err:XPST0017 Call to undeclared function: local:toto [at line 1, column 1, source: local:toto()]
Your help is appreciated.
You have syntax errors in your XQuery:
You have two functions named local:toto(). Each function must have a distinct name.
There is no semicolon following the function definition, i.e. } should be };.
Also you should remove the return expression, as there is no preceding binding.
Another option would be to parameterize the input file, e.g.:
import module namespace request="http://exist-db.org/xquery/request";
declare function local:toto($name as xs:string) as node() {
let $doc :=
if($name eq "carmen")then
doc("/db/ProjetXML/carmen.xml")
else
doc("/db/ProjetXML/alice.xml")
return
$doc/raweb/identification/projectName);
};
local:toto(request:get-parameter("name", "alice"))
You can then call this via the REST Server using a URL like:
http://localhost:8080/exist/rest/db/ProjetXML/orange.xqy?name=carmen
Related
I'm using baseX in a REST environment and I'm quite stuck trying to run an .xq script with an undefined number of GET variables (could be 1 but could be 10)
I'd like to make my xq script generic about that and construct my query independently.
Is there a way to achieve that, playing with array or sending differently my variables, or I dunno how ?
here is my API call
http://basex:8984/rest/?run=WEB-INF/data/test.xq&$tag=p&value=sciences&tag2=p&value2=test&tag3=testdzq
here is my text.xq
declare variable $tag external;
declare variable $value external;
declare variable $tag2 external;
declare variable $value2 external;
<documents>
{for $doc in collection("testdb2")
where $doc//*[name() eq $tag]/text()[matches(., $value )]
and $doc//*[name() eq $tag2]/text()[matches(., $value2 )]
return <doc>{$doc//titleStmt/title/text()}</doc>
}
</documents>
Thanks !
found this here (see http-params function) https://www.balisage.net/Proceedings/vol18/print/Murray01/BalisageVol18-Murray01.html
(: BaseX example :)
(: In the controller ... :)
module namespace c = "http://balisage.net/ns/Bal2016murr0319/controller";
import module namespace request = "http://exquery.org/ns/request";
import module namespace item = "http://balisage.net/ns/Bal2016murr0319/views/item" at "views/item.xqm";
(:~ Returns a map containing the HTTP request parameters. :)
declare function c:http-params()
as map(*)
{
map:merge(
for $name in request:parameter-names()
let $value := request:parameter($name)
return map:entry($name, $value)
)
};
(:~ Calls the appropriate view, based on user input. :)
declare function c:get-view()
as element(html)
{
(: get HTTP request parameters :)
let $params := c:http-params()
return
if (map:get($params, "id")) then
(: the presence of "id" indicates that the user is requesting the item-level page for this unique identifier :)
(: call the item-level view :)
item:get-html($params)
else if ... (: call some other view :)
else if ... (: call some other view :)
else (: call the view for the home page ... :)
};
I'm using OSM 7.2.0.3 and I have cartridge with an Order Recognition Rule, with its Order Data Rule (inside Transformation tab)
In the ODR I have this XQuery code:
declare namespace im="http://xxx";
declare namespace xs="http://www.w3.org/2001/XMLSchema";
declare variable $order := fn:root(.)/im:Order;
<_root>
<Order>
{
for $moli in $order/MainOrderLineItem
return {
<OrderLineItem>
{$moli/LineItemAttributeInfo/LineItemAttribute}
</OrderLineItem>
{
for $oli in $moli/OrderLineItem
return
<OrderLineItem>
{$oli/LineItemAttributeInfo/LineItemAttribute}
</OrderLineItem>
}
}
}
</Order>
</_root>
There's no compile error in OSM, but on runtime I get:
Invalid Order Specification Fault
Order data expression failed due to oracle.communications.ordermanagement.rule.XMLRuleException
I run the OSM by submitting an XML through Web Service.
Thanks a lot for your replies.
The returned XML should actually be in parentheses instead of braces. There also needs to be a comma between the first returned OrderLineItem element and the FLWOR expression instead of wrapping it in braces:
declare namespace im="http://xxx";
declare namespace xs="http://www.w3.org/2001/XMLSchema";
declare variable $order := fn:root(.)/im:Order;
<_root>
<Order>{
for $moli in $order/MainOrderLineItem
return (
<OrderLineItem>
{$moli/LineItemAttributeInfo/LineItemAttribute}
</OrderLineItem>,
for $oli in $moli/OrderLineItem
return
<OrderLineItem>
{$oli/LineItemAttributeInfo/LineItemAttribute}
</OrderLineItem>
)
}</Order>
</_root>
Is is-node-in-sequence-deep-equal in XQuery? I'm wondering because I've seen the function at xqueryfunctions.com, but I'm not being able to use it.
That function is part of the FunctX XQuery library. There are two methods to use this function:
You download the whole library (select the download which corresponds to your version of XQuery), save it in the same directory as your XQuery program/file and then import the module in your XQuery file, e.g.:
import module namespace functx = "http://www.functx.com" at "functx-1.0-doc-2007-01.xq";
(: Insert your code here and call the is-node-in-sequence-deep-equal function as seen below :)
functx:is-node-in-sequence-deep-equal($node, $seq)
Instead of downloading the whole library with all functions you can also simply copy paste the specific function which you need as shown on the page you linked to:
declare namespace functx = "http://www.functx.com";
declare function functx:is-node-in-sequence-deep-equal
( $node as node()? ,
$seq as node()* ) as xs:boolean {
some $nodeInSeq in $seq satisfies deep-equal($nodeInSeq,$node)
} ;
(: Insert your code here and call the 'is-node-in-sequence-deep-equal' function as seen below :)
functx:is-node-in-sequence-deep-equal($node, $seq)
In both examples you simply replace $node and $seq with your variables.
I have a content.xml modelled as below
<root>
<childnode>
Some text here
</childnode>
</root>
I am trying to remove the <childnode> and update the content.xml with only the value of it
so the output looks like
<root>
Some Text here
</root>
I wrote a function to perform this but anytime I run it it gives me error as "unexpected token: modify". I was thinking of a way to accomplish this without using functx functions.
xquery version "1.0";
declare namespace request="http://exist-db.org/xquery/request";
declare namespace file="http://exist-db.org/xquery/file";
declare namespace system="http://exist-db.org/xquery/system";
declare namespace util="http://exist-db.org/xquery/util";
declare namespace response="http://exist-db.org/xquery/response";
declare function local:contentUpdate() {
let $root := collection('/lib/repository/content')//root/childNode
let $rmChild := for $child in $root
modify
(
return rename node $child as ''
)
};
local:updateTitle()
Thanks in advance
There are multiple problems with your query:
Updating functions must be declared as updating.
You're calling another function than you defined (probably you didn't notice as there still have been syntax errors).
Rename node expects some element (or processing instruction, attribute) as target, the empty string is not allowed.
At least BaseX doesn't allow updating statements when defining code as XQuery 1.0. Maybe exist doesn't care about this, try adding it if you need to know.
You do not want to rename, but replace all <childnode />s with its contents, use replace node.
This code fixes all these problems:
declare updating function local:contentUpdate() {
let $root := collection('/lib/repository/content')
return
for $i in $root//childnode
return
replace node $i with $i/data()
};
local:contentUpdate()
eXist-db's XQuery Update syntax is documented at http://exist-db.org/exist/update_ext.xml. Note that this syntax predates the release of the XQuery Update Facility 1.0, so the syntax is different and remains unique to eXist-db.
The way to do what you want in eXist-db is as follows:
xquery version "1.0";
declare function local:contentUpdate() {
let $root := doc('/db/lib/repository/content/content.xml')/root
return
update value $root with $root/string()
};
local:contentUpdate()
The primary changes, compared to your original code, are:
Inserted the eXist-db syntax for your update
Prepended '/db' to your collection name, as /db is the root of the database in eXist-db; replaced the collection() call with a doc() call, since you stated you were operating on a single file, content.xml
Changed //root to /root, since "root" is the root element, so the // (descendant-or-self) axis is extraneous
Replaced updateTitle() with the actual name of the function, contentUpdate
Removed the extraneous namespace declarations
For more on why I used $root/string(), see http://community.marklogic.com/blog/text-is-a-code-smell.
Is it possible to declare a variable to be used only inside of function declaration? If so - how to do it?
Variable declaration can only be placed in the prolog of a query, but you can wrap your function code with a FLWOR expression, consisting of a single LET and RETURN clause. An example:
declare function local:func() {
let $var := ...your variable...
return
...your actual code...
};
Hope this helps,
Christian
You can use XQuery Scripting to declare local variables.
declare %a:sequential function local:func() {
variable $var := ....;
...actual code...
}
XQuery Scripting is described in the following tutorial: http://www.zorba-xquery.com/site2/doc/latest/zorba/html/scripting_tutorial.html